[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