On Tue, Mar 3, 2009 at 11:56 AM, Juan Vuletich <juan@jvuletich.org> wrote:
Hi Eliot,

Eliot Miranda wrote:
Hi Juan,


On Tue, Mar 3, 2009 at 5:28 AM, Juan Vuletich <juan@jvuletich.org <mailto:juan@jvuletich.org>> wrote:

   Hi Andreas,

   Andreas Raab wrote:

       ...

       This is tricky with MessageTally. There are several issues to
       keep in mind, some of which you can fix, some of which you
       can't. Here we go:

       1) Observing all Processes
       --------------------------
       First, MessageTally only observes the block you are running,
       not the entire system. For example, if you were to profile this:

       done := Semaphore new.
       worker:= [
          10 timesRepeat:[World changed; displayWorld].
          done signal.
       ] fork.
       MessageTally spyOn:[done wait].

       This is what you'd get:

       **Tree**
       100.0% {2367ms} primitives

       **Leaves**
       100.0% {2367ms} UndefinedObject>>DoIt

       Obviously it's not actually measuring what is going on during
       the period of time which is a real problem if you are trying
       to measure server load in general. But it's fixable.
       ...

   I found all this stuff very interesting and useful. Thanks!

   WRT issue 1), what I'd really like is the tally tree to have
   several roots, one for each forked process. Otherwise, the process
   that forks other processes would also have their tallies added to
   him (which is wrong, as it would appear to be using more time than
   it really did). Fixing this, MessageTally could give a better
   insight on cpu usage than #tallyCPUUsageFor:.

   To do this, I'd need to find out for a certain context in the
   sender chain, on which process it was running. (Then, when
   building the tally tree, I could know that I need to add a new
   root.) Do you know how to find out? I spent a couple of hours on
   this, and it seems it is not possible...


When MessageTally runs to collect each tally the process that has been interrupted is the highest priority runnable process in the runnable process lists in ProcessorScheduler.  You could implement it like this:

!ProcessorScheduler methodsFor: 'accessing' stamp: 'eem 3/3/2009 10:41'!
highestPriorityRunnableProcess
[quiescentProcessLists reverseDo:
[:each| each isEmpty ifFalse: [^each first]]] valueUnpreemptively.
^nil

"| thisProcess interruptedProcess done |
thisProcess := Processor activeProcess.
done := false.
[(Delay forSeconds: 1) wait.
interruptedProcess := Processor highestPriorityRunnableProcess.
done := true] forkAt: Processor userInterruptPriority.
[done] whileFalse.
self assert: thisProcess == interruptedProcess"! !

So modify MessageTally (or better still create a subclass called MultiProcessMessageTally) that uses the above to manage a set of tallies for each process found while spying.

HTH


What you say sounds similar to what Andreas suggests to make MessageTally spy over all processes. The issue I point out is that when MessageTally
builds the tree, the sender of a context might be in another process. This happens when a context forks a new process, it is still its sender. So when building the tally tree, I need to query each context for the process running it, and when it is different from the parent's one, I'll start a new tally tree.

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.



Cheers,
Juan Vuletich