[squeak-dev] Re: How to profile a server image?
Juan Vuletich
juan at jvuletich.org
Wed Mar 4 01:28:48 UTC 2009
Hi Eliot,
Eliot Miranda wrote:
>
> ...
>
> I think I see but I wouldn't put it like that. Yes, new processes get
> resumed in the context of other proesses, but no, the sender is not in
> another process. The bottom context of a process has no sender. So
> why bother at all trying to track down in which process a process was
> created and leave that to the user when interpreting the profile?
>
> I made it work, by adding an ivar to Process to hold the
> firstContext (the one that is sent to #forContext:priority:).
> Then, when building the tally tree, for each context, I check if
> it is the firstContext of some process. The problem with this
> approach is that it adds too much overhead to the tally.
>
>
> IMO just throw this away. You don't absolutely need to know on behalf
> of which process a process is running.
>
> I'd really appreciate a better way to do this. I'm sure everybody
> will like the multi-process tally that would result!
>
>
> I believe the VW multi-process profiler doesn't bother identifying the
> parent process. But if it does it can do so by e.g. adding an inst
> var to process that refers to the parent process, rather than the
> context in which the process was created. But both recording the
> context or the parent process are bad ideas for garbage collection.
>
> I would simply use the process name facility (Process>>name[:] as
> displayed by the process browser) to label the various tallies you
> collect. If a user can't work out which process is which by just
> looking at the the profile ten they can change their code to use
> Process>>name: to add names to various processes and then be able to
> wrk it out.
>
> just my 2¢
>
> best
> E.
I'm not interested at all on identifying the parent process. To make my
aim clearer, let's see an example:
[1000 timesRepeat: [3.14159 printString. Processor yield]] fork.
[1000 timesRepeat: [30 factorial. Processor yield]] fork.
[1000 timesRepeat: [30 factorial. Processor yield]] fork.
MessageTally spyOn: [ (Delay forMilliseconds: 100) wait]
Without Andreas fixes, it gives a completely useless answer, as if all
the time was spent in the Delay.
With Andreas' fix, it gives:
**Tree**
55.0% {55ms} SmallInteger(Integer)>>factorial
|50.0% {50ms} SmallInteger(Integer)>>factorial
| 47.0% {47ms} SmallInteger(Integer)>>factorial
| 42.0% {42ms} SmallInteger(Integer)>>factorial
| 39.0% {39ms} SmallInteger(Integer)>>factorial
| 33.0% {33ms} SmallInteger(Integer)>>factorial
| 30.0% {30ms} SmallInteger(Integer)>>factorial
| 23.0% {23ms} SmallInteger(Integer)>>factorial
| 22.0% {22ms} SmallInteger(Integer)>>factorial
| 18.0% {18ms} SmallInteger(Integer)>>factorial
| 18.0% {18ms} SmallInteger(Integer)>>factorial
| 16.0% {16ms} SmallInteger(Integer)>>factorial
| 14.0% {14ms} SmallInteger(Integer)>>factorial
| 11.0% {11ms} SmallInteger(Integer)>>factorial
23.0% {23ms} Float(Object)>>printString
23.0% {23ms} Float(Object)>>printStringLimitedTo:
20.0% {20ms} Float(Number)>>printOn:
18.0% {18ms} Float>>printOn:base:
18.0% {18ms} Float>>absPrintOn:base:
It could separate the first forked process, but only because it runs
different code (#printString). Both processes running #factorial are
shown together. It is true that a context with no sender (the bottom of
a stack) is a root at the tree. But we can not know to which process
they belong. Therefore I can not decorate each tree with a process name!
What I can get with my code is:
**Tree**
-----------------------------------
unknown process
-----------------------------------
29.2% {31ms} BlockContext>>newProcess
|29.2% {31ms} ProcessorScheduler class>>startUp
| 29.2% {31ms} ProcessorScheduler class>>idleProcess
-----------------------------------
(40) process named: 1992
-----------------------------------
28.3% {30ms} MessageTally class>>DoIt
|28.3% {30ms} SmallInteger(Integer)>>timesRepeat:
| 26.4% {28ms} MessageTally class>>DoIt
| 26.4% {28ms} Float(Object)>>printString
| 25.5% {27ms} Float(Object)>>printStringLimitedTo:
| 25.5% {27ms} String class(SequenceableCollection
class)>>streamContents:limitedTo:
| 22.6% {24ms} Float(Object)>>printStringLimitedTo:
| 22.6% {24ms} Float(Number)>>printOn:
| 21.7% {23ms} Float>>printOn:base:
| 21.7% {23ms} Float>>absPrintOn:base:
-----------------------------------
(40) process named: 2910
-----------------------------------
17.9% {19ms} MessageTally class>>DoIt
|17.9% {19ms} SmallInteger(Integer)>>timesRepeat:
| 17.0% {18ms} MessageTally class>>DoIt
| 17.0% {18ms} SmallInteger(Integer)>>factorial
| 15.1% {16ms} SmallInteger(Integer)>>factorial
| 12.3% {13ms} SmallInteger(Integer)>>factorial
-----------------------------------
(40) process named: 893
-----------------------------------
15.1% {16ms} MessageTally class>>DoIt
15.1% {16ms} SmallInteger(Integer)>>timesRepeat:
15.1% {16ms} MessageTally class>>DoIt
15.1% {16ms} SmallInteger(Integer)>>factorial
14.2% {15ms} SmallInteger(Integer)>>factorial
14.2% {15ms} SmallInteger(Integer)>>factorial
13.2% {14ms} SmallInteger(Integer)>>factorial
13.2% {14ms} SmallInteger(Integer)>>factorial
I can get the tally for each process. Many times this will be much
easier to optimize the application, especially if each process can have
a meaningful name, and a well known purpose.
If you say that the process holding a reference to the first context it
ran is bad for GC, I take your word. But I'd really like to solve this
problem.
Thanks,
Juan Vuletich
More information about the Squeak-dev
mailing list
|