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 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.
I'd really appreciate a better way to do this. I'm sure everybody will like the multi-process tally that would result!
Cheers, Juan Vuletich