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