2009/3/4 Andreas Raab <[hidden email]>:
> Igor Stasenko wrote: >> >> Guys, can i ask you to put these recommendations on wiki page, so this >> VERY USEFUL guide will not be buried in mailing list and can serve as >> a basic guide for profiling in Squeak? > > Where would you put it? I have never found my way through the Wiki. If it's > helpful for others I'd be happy to put it up, just tell me where you'd like > it to go. > There is a wiki page, already dedicated to it http://wiki.squeak.org/squeak/1799 Or , maybe its worth create a new page 'Profiling in Squeak' .. or give it more appropriate name > Cheers, > - Andreas > > -- Best regards, Igor Stasenko AKA sig. |
In reply to this post by Eliot Miranda-2
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 |
In reply to this post by Andreas.Raab
Hi Andreas,
Andreas Raab wrote: > Juan Vuletich wrote: >> 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'm not sure how useful this is. When it comes to measuring where the > time goes, the cumulative tree of multiple processes shows you if you > have deficiencies in the core framework handling. This is extremely > useful. And it breaks down quite nicely into separate pieces where > actual different work is involved. I don't think you would get much > more useful information if you were to break things apart. And I can > say for sure that for the purposes of our server profiling it would be > pretty much useless - under load we run literally hundreds of processes. > > Cheers, > - Andreas > > > I understand that for a server having an variable (and big) number of processes it is not useful. But for our case, an application with a small and fixed set of processes, the first question we want to answer is "which is the process using all the cpu?". Please see the message I just sent on this thread to see an example of what I want. Thanks, Juan Vuletich |
In reply to this post by Juan Vuletich-4
Juan Vuletich wrote:
> 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. Ah, very good! I've been looking for an example that illustrates just that. This is extremely helpful. For our purposes (lots of processes, you want to profile overall server behavior) the cumulative tree is the only useful response. There would be no point whatsoever even trying to separate hundreds of processes (it is statistical profiling after all). However, I can see that in some situations your view might be useful for some people. I would guess that the easiest way to distinguish processes would be look at the identity of the context that is at the root of the call tree. If you send me the code I'll see if I can come up with a clever way to have our cake and eat it, too. Cheers, - Andreas |
In reply to this post by Igor Stasenko
Igor Stasenko wrote:
> There is a wiki page, already dedicated to it > http://wiki.squeak.org/squeak/1799 > > Or , maybe its worth create a new page 'Profiling in Squeak' .. or > give it more appropriate name Now up at http://wiki.squeak.org/squeak/6122 Which reminds me: I had forgotten how much I hate the Swiki. It is ugly, horribly conflated, and effectively unusable. Should we replace the damn thing with a community blog instead? I think this might be a better way of dealing with the information overload - you get dated, tagged entry and if we keep this open for pretty much every member of the community (using the "standard" username/password from the Swiki) we could use it much the same. I'd be more than willing to write up my post as a blog article instead. I just don't have a blog and even if I had I doubt many people would use it. A community blog could be a nice, lively place to post your thoughts in a bit more organized manner and would make an attractive target for people who just want to know what's going on in the world of Squeak. Cheers, - Andreas |
2009/3/4 Andreas Raab <[hidden email]>:
> Igor Stasenko wrote: >> >> There is a wiki page, already dedicated to it >> http://wiki.squeak.org/squeak/1799 >> >> Or , maybe its worth create a new page 'Profiling in Squeak' .. or >> give it more appropriate name > > Now up at http://wiki.squeak.org/squeak/6122 > > Which reminds me: I had forgotten how much I hate the Swiki. It is ugly, > horribly conflated, and effectively unusable. Should we replace the damn > thing with a community blog instead? I think this might be a better way of > dealing with the information overload - you get dated, tagged entry and if > we keep this open for pretty much every member of the community (using the > "standard" username/password from the Swiki) we could use it much the same. > > I'd be more than willing to write up my post as a blog article instead. I > just don't have a blog and even if I had I doubt many people would use it. A > community blog could be a nice, lively place to post your thoughts in a bit > more organized manner and would make an attractive target for people who > just want to know what's going on in the world of Squeak. > we had a http://people.squeak.org/ which has a kind of blogging facilities, but now it looks like dead. The page is different. P.S. +1 for having a community blog. > Cheers, > - Andreas > > > -- Best regards, Igor Stasenko AKA sig. |
In reply to this post by Andreas.Raab
+1
Steve On 3 Mar 2009, at 18:25, Andreas Raab <[hidden email]> wrote: > Igor Stasenko wrote: >> There is a wiki page, already dedicated to it >> http://wiki.squeak.org/squeak/1799 >> Or , maybe its worth create a new page 'Profiling in Squeak' .. or >> give it more appropriate name > > Now up at http://wiki.squeak.org/squeak/6122 > > Which reminds me: I had forgotten how much I hate the Swiki. It is > ugly, horribly conflated, and effectively unusable. Should we > replace the damn thing with a community blog instead? I think this > might be a better way of dealing with the information overload - you > get dated, tagged entry and if we keep this open for pretty much > every member of the community (using the "standard" username/ > password from the Swiki) we could use it much the same. > > I'd be more than willing to write up my post as a blog article > instead. I just don't have a blog and even if I had I doubt many > people would use it. A community blog could be a nice, lively place > to post your thoughts in a bit more organized manner and would make > an attractive target for people who just want to know what's going > on in the world of Squeak. > > Cheers, > - Andreas > > |
In reply to this post by Juan Vuletich-4
Juan Vuletich wrote:
> I understand that for a server having an variable (and big) number of > processes it is not useful. But for our case, an application with a > small and fixed set of processes, the first question we want to answer > is "which is the process using all the cpu?". Please see the message I > just sent on this thread to see an example of what I want. Okay, I cracked ;-) Attached you'll find patches for a message tally version which does per-process reporting if so desired. I've moved this out of the arguments and into class variables so you get/set either priority or preference via, e.g.: MessageTally spyPriority: <new priority> MessageTally showProcesses: <true/false> The defaults are such that the priority is TimerPriority-1 and showProcesses is on. With it, your example gives the result shown below. Let me know if this works for you (or anyone else). Comments welcome. Cheers, - Andreas - 101 tallies, 101 msec. **Tree** -------------------------------- Process: (40) 3420: [] in UndefinedObject>>DoIt {[3.14159 printString. Processor yield]} -------------------------------- 23.8% {24ms} Float(Number)>>printStringBase: 21.8% {22ms} Float>>printOn:base: 20.8% {21ms} Float>>absPrintOn:base: 6.9% {7ms} False>>| 5.9% {6ms} primitives 3.0% {3ms} WriteStream>>nextPut: -------------------------------- Process: (40) 1426: [] in UndefinedObject>>DoIt {[30 factorial. Processor yield]} -------------------------------- 29.7% {30ms} SmallInteger(Integer)>>factorial 26.7% {27ms} SmallInteger(Integer)>>factorial |24.8% {25ms} SmallInteger(Integer)>>factorial | 22.8% {23ms} SmallInteger(Integer)>>factorial | 21.8% {22ms} SmallInteger(Integer)>>factorial | 20.8% {21ms} SmallInteger(Integer)>>factorial | 16.8% {17ms} SmallInteger(Integer)>>factorial | |14.9% {15ms} SmallInteger(Integer)>>factorial | | 13.9% {14ms} SmallInteger(Integer)>>factorial | | 10.9% {11ms} SmallInteger(Integer)>>factorial | | |8.9% {9ms} SmallInteger(Integer)>>factorial | | | 7.9% {8ms} SmallInteger(Integer)>>factorial | | | 6.9% {7ms} SmallInteger(Integer)>>factorial | | | 5.0% {5ms} SmallInteger(Integer)>>factorial | | | 5.0% {5ms} SmallInteger(Integer)>>factorial | | | 3.0% {3ms} SmallInteger(Integer)>>factorial | | | 3.0% {3ms} SmallInteger(Integer)>>factorial | | 3.0% {3ms} SmallInteger>>* | 4.0% {4ms} SmallInteger>>* 3.0% {3ms} SmallInteger>>* -------------------------------- Process: (40) 3777: [] in UndefinedObject>>DoIt {[30 factorial. Processor yield]} -------------------------------- 40.6% {41ms} SmallInteger(Integer)>>factorial 38.6% {39ms} SmallInteger(Integer)>>factorial 37.6% {38ms} SmallInteger(Integer)>>factorial 35.6% {36ms} SmallInteger(Integer)>>factorial 30.7% {31ms} SmallInteger(Integer)>>factorial |26.7% {27ms} SmallInteger(Integer)>>factorial | |23.8% {24ms} SmallInteger(Integer)>>factorial | | |22.8% {23ms} SmallInteger(Integer)>>factorial | | | 21.8% {22ms} SmallInteger(Integer)>>factorial | | | 21.8% {22ms} SmallInteger(Integer)>>factorial | | | 19.8% {20ms} SmallInteger(Integer)>>factorial | | | 17.8% {18ms} SmallInteger(Integer)>>factorial | | | 14.9% {15ms} SmallInteger(Integer)>>factorial | | | |9.9% {10ms} SmallInteger(Integer)>>factorial | | | | |7.9% {8ms} SmallInteger(Integer)>>factorial | | | | | 5.9% {6ms} SmallInteger(Integer)>>factorial | | | | | 3.0% {3ms} SmallInteger>>* | | | | | 3.0% {3ms} SmallInteger(Integer)>>factorial | | | |5.0% {5ms} SmallInteger>>* | | | | 3.0% {3ms} primitives | | | 3.0% {3ms} SmallInteger>>* | |3.0% {3ms} SmallInteger>>* |4.0% {4ms} SmallInteger>>* 5.0% {5ms} SmallInteger>>* 3.0% {3ms} primitives **Leaves** 51.5% {52ms} SmallInteger>>* 7.9% {8ms} SmallInteger(Number)>>negative 6.9% {7ms} False>>| 5.9% {6ms} Float>>absPrintOn:base: 5.0% {5ms} SmallInteger(Integer)>>* 5.0% {5ms} False(ProtoObject)>>~~ 4.0% {4ms} SmallInteger(Integer)>>factorial **Memory** old +0 bytes young -70,492 bytes used -70,492 bytes free +70,492 bytes **GCs** full 0 totalling 0ms (0.0% uptime) incr 17 totalling 13ms (13.0% uptime), avg 1.0ms tenures 0 root table 0 overflows MessageTallyEnh-ar.2.cs (8K) Download Attachment |
In reply to this post by Andreas.Raab
+1
Larry Trutter > Date: Tue, 3 Mar 2009 18:25:35 -0800 > From: [hidden email] > To: [hidden email] > Subject: [squeak-dev] Community blog? (was: Re: How to profile a server image?) > > Igor Stasenko wrote: > > There is a wiki page, already dedicated to it > > http://wiki.squeak.org/squeak/1799 > > > > Or , maybe its worth create a new page 'Profiling in Squeak' .. or > > give it more appropriate name > > Now up at http://wiki.squeak.org/squeak/6122 > > Which reminds me: I had forgotten how much I hate the Swiki. It is ugly, > horribly conflated, and effectively unusable. Should we replace the damn > thing with a community blog instead? I think this might be a better way > of dealing with the information overload - you get dated, tagged entry > and if we keep this open for pretty much every member of the community > (using the "standard" username/password from the Swiki) we could use it > much the same. > > I'd be more than willing to write up my post as a blog article instead. > I just don't have a blog and even if I had I doubt many people would use > it. A community blog could be a nice, lively place to post your thoughts > in a bit more organized manner and would make an attractive target for > people who just want to know what's going on in the world of Squeak. > > Cheers, > - Andreas > > Windows Live™ Contacts: Organize your contact list. Check it out. |
In reply to this post by Juan Vuletich-4
A long time ago I suggested that you could track CPU usage, or
dispatch clock time in Interpreter>>transferTo: aProc since that still is the only place a transfer switch occurs between processes. You could collect more things too, like network traffic etc. I've always thought the benefit is that you don't have some ugly high priority watcher task thundering about creating garbage and leaving foot prints in the cake... http://lists.squeakfoundation.org/pipermail/squeak-dev/2001-March/015945.html On 3-Mar-09, at 5:31 PM, Juan Vuletich wrote: > Hi Andreas, > > Andreas Raab wrote: >> Juan Vuletich wrote: >>> 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'm not sure how useful this is. When it comes to measuring where >> the time goes, the cumulative tree of multiple processes shows you >> if you have deficiencies in the core framework handling. This is >> extremely useful. And it breaks down quite nicely into separate >> pieces where actual different work is involved. I don't think you >> would get much more useful information if you were to break things >> apart. And I can say for sure that for the purposes of our server >> profiling it would be pretty much useless - under load we run >> literally hundreds of processes. >> >> Cheers, >> - Andreas >> >> >> > > I understand that for a server having an variable (and big) number > of processes it is not useful. But for our case, an application with > a small and fixed set of processes, the first question we want to > answer is "which is the process using all the cpu?". Please see the > message I just sent on this thread to see an example of what I want. > > Thanks, > Juan Vuletich > -- = = = ======================================================================== John M. McIntosh <[hidden email]> Corporate Smalltalk Consulting Ltd. http://www.smalltalkconsulting.com = = = ======================================================================== |
In reply to this post by Andreas.Raab
A blog and a wiki is not for the same purpposes IMHO.
Maybe, could be interesting, migrate the actual wiki, to some new over Seaside-Pier / Aida-Scribo. Cheers. Andreas Raab escribió: > Igor Stasenko wrote: >> There is a wiki page, already dedicated to it >> http://wiki.squeak.org/squeak/1799 >> >> Or , maybe its worth create a new page 'Profiling in Squeak' .. or >> give it more appropriate name > > Now up at http://wiki.squeak.org/squeak/6122 > > Which reminds me: I had forgotten how much I hate the Swiki. It is > ugly, horribly conflated, and effectively unusable. Should we replace > the damn thing with a community blog instead? I think this might be a > better way of dealing with the information overload - you get dated, > tagged entry and if we keep this open for pretty much every member of > the community (using the "standard" username/password from the Swiki) > we could use it much the same. > > I'd be more than willing to write up my post as a blog article > instead. I just don't have a blog and even if I had I doubt many > people would use it. A community blog could be a nice, lively place to > post your thoughts in a bit more organized manner and would make an > attractive target for people who just want to know what's going on in > the world of Squeak. > > Cheers, > - Andreas > > |
In reply to this post by Andreas.Raab
"Andreas Raab" <[hidden email]> wrote:
> Igor Stasenko wrote: > > There is a wiki page, already dedicated to it > > http://wiki.squeak.org/squeak/1799 > > > > Or , maybe its worth create a new page 'Profiling in Squeak' .. or > > give it more appropriate name > > Now up at http://wiki.squeak.org/squeak/6122 > > Which reminds me: I had forgotten how much I hate the Swiki. It is ugly, > horribly conflated, and effectively unusable. Should we replace the damn > thing with a community blog instead? I think this might be a better way > of dealing with the information overload - you get dated, tagged entry > and if we keep this open for pretty much every member of the community > (using the "standard" username/password from the Swiki) we could use it > much the same. > > I'd be more than willing to write up my post as a blog article instead. > I just don't have a blog and even if I had I doubt many people would use > it. A community blog could be a nice, lively place to post your thoughts > in a bit more organized manner and would make an attractive target for > people who just want to know what's going on in the world of Squeak. Well, I'd follow your blog, for one. But http://planet.squeak.org/ is pretty darn cool: start your own blog, and have the planet aggregate it. Or there's Yahoo! Pipes, described by Bill Clementson here: http://bc.tech.coop/blog/081206.html The concept's the same, at any rate: instead of a single community blog, there's a single blog aggregator, fed by multiple personal blogs. frank |
>
> Well, I'd follow your blog, for one. But http://planet.squeak.org/ is pretty > darn cool: start your own blog, and have the planet aggregate it. I'd better use our own tool, a kind of mix between blog and wiki... using rights to allow some other people to modify/complete some posts... I think we have it already minus some particularities, it's more a question of organization. One thing I'll find important is to define a common set of tags (topics, level of completion, importance, documentation type, deprecation (st version concerned) etc...). Voting on relevance cound be nice too... Having proper developper/person profile would be of high interest to me too... so that a beginner can find post written by beginner, tutorial for beginners, etc... If you "like" someone, you can get his posts/modifs/comments plus the ones of people that are "similar" to him... ... Just my 2 cents ;) > > Or there's Yahoo! Pipes, described by Bill Clementson here: > http://bc.tech.coop/blog/081206.html > > The concept's the same, at any rate: instead of a single community blog, > there's a single blog aggregator, fed by multiple personal blogs. > > frank > > > -- Cédrick |
In reply to this post by Frank Shearar
On 04.03.2009, at 10:01, Frank Shearar wrote: > http://planet.squeak.org/ is pretty > darn cool: start your own blog, and have the planet aggregate it. > > The concept's the same, at any rate: instead of a single community > blog, > there's a single blog aggregator, fed by multiple personal blogs. It would be more useful if the individual feeds were only for those blog posts tagged "squeak" ... for my taste too many non-squeak related posts make it to the planet. Most blog engines allow to tag posts, and to get feeds for specific tags only. Those filtered feeds should get aggregated, not every "guitar hero" blurb ;) - Bert - |
In reply to this post by johnmci
On Tue, Mar 03, 2009 at 09:06:16PM -0800, John M McIntosh wrote:
> A long time ago I suggested that you could track CPU usage, or > dispatch clock time in > Interpreter>>transferTo: aProc since that still is the only place a > transfer switch occurs between processes. > You could collect more things too, like network traffic etc. > I've always thought the benefit is that you don't have some ugly high > priority watcher task thundering about > creating garbage and leaving foot prints in the cake... > > > http://lists.squeakfoundation.org/pipermail/squeak-dev/2001-March/015945.html Wow, back then the biggest impediment to progress was your 14400 baud modem ("just try doing uploads etc at 14400 baud") ! ;) |
In reply to this post by Bert Freudenberg
Hi!
Bert Freudenberg wrote: > It would be more useful if the individual feeds were only for those blog > posts tagged "squeak" ... for my taste too many non-squeak related posts > make it to the planet. Most blog engines allow to tag posts, and to get > feeds for specific tags only. Those filtered feeds should get > aggregated, not every "guitar hero" blurb ;) We just set up a Venus aggregator here at MSC - Venus is the enhanced version of Planet that has filtering capabilities. Then you can filter on categories/tags etc. Furthermore - a blog aggregator (or community blog - but a blog aggregator is IMHO smarter) serves a different purpose than a wiki. I would though consider setting up a new "purged" wiki that "starts over" from scratch and perhaps tries to limits itself in what it documents - like perhaps from a given version of Squeak and forward. regards, Göran |
In reply to this post by Andreas.Raab
+1. blog is the way to go.
It *could* be st based but it *hasn't* necessarily to be st based. Design matters so it *hasn't* to hurt the eye when you see it. Today that could be more important than bloating it with features. cheers, sebastian > -----Mensaje original----- > De: [hidden email] > [mailto:[hidden email]] En > nombre de Andreas Raab > Enviado el: Tuesday, March 03, 2009 23:26 > Para: The general-purpose Squeak developers list > Asunto: [squeak-dev] Community blog? (was: Re: How to profile > a serverimage?) > > Igor Stasenko wrote: > > There is a wiki page, already dedicated to it > > http://wiki.squeak.org/squeak/1799 > > > > Or , maybe its worth create a new page 'Profiling in Squeak' .. or > > give it more appropriate name > > Now up at http://wiki.squeak.org/squeak/6122 > > Which reminds me: I had forgotten how much I hate the Swiki. > It is ugly, > horribly conflated, and effectively unusable. Should we > replace the damn > thing with a community blog instead? I think this might be a > better way > of dealing with the information overload - you get dated, > tagged entry > and if we keep this open for pretty much every member of the > community > (using the "standard" username/password from the Swiki) we > could use it > much the same. > > I'd be more than willing to write up my post as a blog > article instead. > I just don't have a blog and even if I had I doubt many > people would use > it. A community blog could be a nice, lively place to post > your thoughts > in a bit more organized manner and would make an attractive > target for > people who just want to know what's going on in the world of Squeak. > > Cheers, > - Andreas > > |
In reply to this post by Andreas.Raab
Hi Andreas,
Andreas Raab wrote: > Juan Vuletich wrote: >> I understand that for a server having an variable (and big) number of >> processes it is not useful. But for our case, an application with a >> small and fixed set of processes, the first question we want to >> answer is "which is the process using all the cpu?". Please see the >> message I just sent on this thread to see an example of what I want. > > Okay, I cracked ;-) Attached you'll find patches for a message tally > version which does per-process reporting if so desired. I've moved > this out of the arguments and into class variables so you get/set > either priority or preference via, e.g.: > > MessageTally spyPriority: <new priority> > MessageTally showProcesses: <true/false> > > The defaults are such that the priority is TimerPriority-1 and > showProcesses is on. With it, your example gives the result shown below. > > Let me know if this works for you (or anyone else). Comments welcome. > > Cheers, > - Andreas firstContext to each process, I also realized it is not necessary at all. But before I could get the tallies properly built, I went to sleep, and you did it! Thanks! I found a small bug, though. You forgot to actually use the class var SpyPriority. The attached change is based on yours, but with a few differences (some of them you might like, some others you might not like :) - If you tally a single process via #spyEvery:onProcess:forMilliseconds: (for example using the option in the ProcessBrowser) you'll get bogus results, as all tallies are captured as if they belonged to the observed process. I fixed it. This one is important. - I left the old #spyOn: for spying on a single process, with the fix I just mentioned to report realistic results. I added #spyAllOn: to spy on all the running processes. I believe many times one might want to spy on just one process. - I removed the SpyPriority classVar. If spying on all processes, I use a really high priority. If spying on single process, I use a slightly higher priority than his (using a a really high priority would not hurt, though). This is just a matter of taste. - I removed the old ObservedProcess class var, as it is no longer necessary. - Allowed for more visible tabs (just cosmetic). - Show nodes using more than 1% (instead of 2%). Not very important. - Modified the menu options in World menu / Debug, to allow for both tallyin the UI or all the system, and to make this clear. That's all. I hope you and others find it useful. Cheers, Juan Vuletich 'From Squeak3.10.2 of ''5 June 2008'' [latest update: #7179] on 4 March 2009 at 10:44:49 am'! Magnitude subclass: #MessageTally instanceVariableNames: 'class method tally receivers senders time gcStats maxClassNameSize maxClassPlusSelectorSize maxTabs process ' classVariableNames: 'DefaultPollPeriod ObservedProcess Timer ShowProcesses ' poolDictionaries: '' category: 'System-Tools'! !MessageTally methodsFor: 'comparing' stamp: 'ar 3/3/2009 19:36'! = aMessageTally self species == aMessageTally species ifFalse: [^ false]. ^ aMessageTally method == method and:[aMessageTally process == process]! ! !MessageTally methodsFor: 'initialize-release' stamp: 'jmv 3/4/2009 10:35'! close (Timer isMemberOf: Process) ifTrue: [Timer terminate]. Timer := nil. class := method := tally := receivers := nil! ! !MessageTally methodsFor: 'initialize-release' stamp: 'jmv 3/4/2009 10:40'! spyAllEvery: millisecs on: aBlock "Create a spy and spy on the given block at the specified rate." "Spy all the system processes" | myDelay startTime time0 observedProcess | (aBlock isMemberOf: BlockContext) ifFalse: [self error: 'spy needs a block here']. self class: aBlock receiver class method: aBlock method. "set up the probe" myDelay := Delay forMilliseconds: millisecs. time0 := Time millisecondClockValue. gcStats := SmalltalkImage current getVMParameters. Timer := [ [true] whileTrue: [ startTime := Time millisecondClockValue. myDelay wait. observedProcess := Processor preemptedProcess. self tally: observedProcess suspendedContext in: (ShowProcesses ifTrue: [observedProcess]) "tally can be > 1 if ran a long primitive" by: (Time millisecondClockValue - startTime) // millisecs]. nil] newProcess. Timer priority: Processor timingPriority-1. "activate the probe and evaluate the block" Timer resume. ^ aBlock ensure: [ "Collect gc statistics" SmalltalkImage current getVMParameters keysAndValuesDo: [ :idx :gcVal | gcStats at: idx put: (gcVal - (gcStats at: idx))]. "cancel the probe and return the value" Timer terminate. time := Time millisecondClockValue - time0]! ! !MessageTally methodsFor: 'initialize-release' stamp: 'jmv 3/4/2009 10:41'! spyEvery: millisecs on: aBlock "Create a spy and spy on the given block at the specified rate." "Spy only on the active process (in which aBlock is run)" | myDelay startTime time0 observedProcess | (aBlock isMemberOf: BlockContext) ifFalse: [self error: 'spy needs a block here']. self class: aBlock receiver class method: aBlock method. "set up the probe" observedProcess _ Processor activeProcess. myDelay := Delay forMilliseconds: millisecs. time0 := Time millisecondClockValue. gcStats := SmalltalkImage current getVMParameters. Timer := [ [true] whileTrue: [ Processor preemptedProcess == observedProcess ifTrue: [ startTime _ Time millisecondClockValue. myDelay wait. self tally: observedProcess suspendedContext in: observedProcess "tally can be > 1 if ran a long primitive" by: (Time millisecondClockValue - startTime) // millisecs]]. nil] newProcess. Timer priority: (observedProcess priority + 1 min: Processor highestPriority). "activate the probe and evaluate the block" Timer resume. ^ aBlock ensure: [ "Collect gc statistics" SmalltalkImage current getVMParameters keysAndValuesDo: [ :idx :gcVal | gcStats at: idx put: (gcVal - (gcStats at: idx))]. "cancel the probe and return the value" Timer terminate. time := Time millisecondClockValue - time0]! ! !MessageTally methodsFor: 'initialize-release' stamp: 'jmv 3/4/2009 10:42'! spyEvery: millisecs onProcess: aProcess forMilliseconds: msecDuration "Create a spy and spy on the given process at the specified rate." | myDelay startTime time0 endTime sem observedProcess | (aProcess isKindOf: Process) ifFalse: [self error: 'spy needs a Process here']. self class: aProcess suspendedContext receiver class method: aProcess suspendedContext method. "set up the probe" observedProcess := aProcess. myDelay := Delay forMilliseconds: millisecs. time0 := Time millisecondClockValue. endTime := time0 + msecDuration. sem := Semaphore new. gcStats := SmalltalkImage current getVMParameters. Timer := [ [ startTime _ Time millisecondClockValue. Processor preemptedProcess == observedProcess ifTrue: [ myDelay wait. self tally: observedProcess suspendedContext in: observedProcess by: Time millisecondClockValue - startTime // millisecs]. startTime < endTime ] whileTrue. sem signal ] forkAt: (observedProcess priority + 1 min: Processor highestPriority). "activate the probe and wait for it to finish" sem wait. "Collect gc statistics" SmalltalkImage current getVMParameters keysAndValuesDo: [ :idx :gcVal | gcStats at: idx put: (gcVal - gcStats at: idx)]. time := Time millisecondClockValue - time0! ! !MessageTally methodsFor: 'printing' stamp: 'ar 3/3/2009 19:43'! fullPrintOn: aStream tallyExact: isExact orThreshold: perCent | threshold | isExact ifFalse: [threshold _ (perCent asFloat / 100 * tally) rounded]. aStream nextPutAll: '**Tree**'; cr. self rootPrintOn: aStream total: tally totalTime: time tallyExact: isExact orThreshold: threshold. aStream nextPut: Character newPage; cr. aStream nextPutAll: '**Leaves**'; cr. self leavesPrintOn: aStream tallyExact: isExact orThreshold: threshold! ! !MessageTally methodsFor: 'printing' stamp: 'ar 3/3/2009 19:47'! rootPrintOn: aStream total: total totalTime: totalTime tallyExact: isExact orThreshold: threshold | sons groups | ShowProcesses ifFalse:[ ^self treePrintOn: aStream tabs: OrderedCollection new thisTab: '' total: total totalTime: totalTime tallyExact: isExact orThreshold: threshold. ]. sons := isExact ifTrue: [receivers] ifFalse: [self sonsOver: threshold]. groups := sons groupBy:[:aTally| aTally process] having:[:g| true]. groups do:[:g| sons := g asSortedCollection. aStream nextPutAll: '--------------------------------'; cr. aStream nextPutAll: 'Process: ', g anyOne process browserPrintString; cr. aStream nextPutAll: '--------------------------------'; cr. (1 to: sons size) do:[:i | (sons at: i) treePrintOn: aStream tabs: OrderedCollection new thisTab: '' total: total totalTime: totalTime tallyExact: isExact orThreshold: threshold]. ].! ! !MessageTally methodsFor: 'reporting' stamp: 'jmv 3/4/2009 09:27'! report: strm "Print a report, with cutoff percentage of each element of the tree (leaves, roots, tree), on the stream, strm." self report: strm cutoff: 1! ! !MessageTally methodsFor: 'tallying' stamp: 'jmv 3/4/2009 10:36'! tally: context by: count "Explicitly tally the specified context and its stack." | sender | "Add to this node if appropriate" context method == method ifTrue: [^self bumpBy: count]. "No sender? Add new branch to the tree." (sender := context home sender)ifNil: [ ^ (self bumpBy: count) tallyPath: context by: count]. "Find the node for the sending context (or add it if necessary)" ^ (self tally: sender by: count) tallyPath: context by: count! ! !MessageTally methodsFor: 'tallying' stamp: 'jmv 3/4/2009 09:42'! tally: context in: aProcess by: count "Explicitly tally the specified context and its stack." | sender | "Add to this node if appropriate" context method == method ifTrue: [^self bumpBy: count]. "No sender? Add new branch to the tree." (sender := context home sender) ifNil: [ ^ (self bumpBy: count) tallyPath: context in: aProcess by: count]. "Find the node for the sending context (or add it if necessary)" ^ (self tally: sender in: aProcess by: count) tallyPath: context in: aProcess by: count! ! !MessageTally methodsFor: 'tallying' stamp: 'jmv 3/4/2009 10:36'! tallyPath: context by: count | aMethod path | aMethod :=context method. "Find the correct child (if there)" receivers do: [ :oldTally | oldTally method == aMethod ifTrue: [path := oldTally]]. "Add new child if needed" path ifNil: [ path := MessageTally new class: context receiver class method: aMethod. receivers := receivers copyWith: path]. ^ path bumpBy: count! ! !MessageTally methodsFor: 'tallying' stamp: 'jmv 3/4/2009 10:38'! tallyPath: context in: aProcess by: count | aMethod path | aMethod := context method. "Find the correct child (if there)" receivers do: [ :oldTally | (oldTally method == aMethod and: [oldTally process == aProcess]) ifTrue: [path := oldTally]]. "Add new child if needed" path ifNil:[ path := MessageTally new class: context receiver class method: aMethod; process: aProcess; maxClassNameSize: maxClassNameSize; maxClassPlusSelectorSize: maxClassPlusSelectorSize; maxTabs: maxTabs. receivers := receivers copyWith: path]. ^ path bumpBy: count! ! !MessageTally methodsFor: 'private' stamp: 'ar 3/3/2009 19:29'! process ^process! ! !MessageTally methodsFor: 'private' stamp: 'ar 3/3/2009 19:29'! process: aProcess process := aProcess! ! !MessageTally class methodsFor: 'defaults' stamp: 'jmv 3/2/2009 12:32'! defaultMaxTabs "Return the default number of tabs after which leading white space is compressed" ^120! ! !MessageTally class methodsFor: 'defaults' stamp: 'jmv 3/4/2009 10:29'! showProcesses "Indicates whether to show each process separately or cumulatively. For example, compare the spy results of the following with both values: [1000 timesRepeat: [3.14159 printString. Processor yield]] fork. [1000 timesRepeat: [30 factorial. Processor yield]] fork. [1000 timesRepeat: [30 factorial. Processor yield]] fork. MessageTally spyAllOn: [ (Delay forMilliseconds: 100) wait] " ^ShowProcesses! ! !MessageTally class methodsFor: 'defaults' stamp: 'jmv 3/4/2009 10:29'! showProcesses: aBool "Indicates whether to show each process separately or cumulatively. For example, compare the spy results of the following with both values: [1000 timesRepeat: [3.14159 printString. Processor yield]] fork. [1000 timesRepeat: [30 factorial. Processor yield]] fork. [1000 timesRepeat: [30 factorial. Processor yield]] fork. MessageTally spyAllOn: [ (Delay forMilliseconds: 100) wait] " ShowProcesses := aBool.! ! !MessageTally class methodsFor: 'spying' stamp: 'jmv 3/4/2009 10:42'! spyAllOn: aBlock "Spy on all the processes in the system [1000 timesRepeat: [3.14159 printString. Processor yield]] fork. [1000 timesRepeat: [20 factorial. Processor yield]] fork. [1000 timesRepeat: [20 factorial. Processor yield]] fork. MessageTally spyAllOn: [ (Delay forMilliseconds: 100) wait] " | node result | node := self new. result := node spyAllEvery: self defaultPollPeriod on: aBlock. (StringHolder new contents: (String streamContents: [:s | node report: s; close])) openLabel: 'Spy Results'. ^ result! ! !MessageTally class methodsFor: 'class initialization' stamp: 'jmv 3/4/2009 09:24'! initialize "MessageTally initialize" "By default, show each process separately" ShowProcesses := true! ! !TheWorldMenu methodsFor: 'commands' stamp: 'jmv 3/4/2009 10:43'! startMessageTally "Tally on all the processes in the system, and not only the UI" (self confirm: 'MessageTally all the processes in the system, until the mouse pointer goes to the top of the screen') ifTrue: [ MessageTally spyAllOn: [ [Sensor peekMousePt y > 0] whileTrue: [World doOneCycle]]]! ! !TheWorldMenu methodsFor: 'construction' stamp: 'jmv 3/4/2009 10:44'! debugMenu | menu | menu _ self menu: 'debug...'. self fillIn: menu from: { { 'inspect world' . { #myWorld . #inspect } }. { 'explore world' . { #myWorld . #explore } }. { 'inspect model' . { self . #inspectWorldModel } }. " { 'talk to world...' . { self . #typeInMessageToWorld } }." { 'MessageTally all Processes' . { self . #startMessageTally } }. { 'MessageTally UI and browse' . { self . #startThenBrowseMessageTally } }. { 'open process browser' . { self . #openProcessBrowser } }. nil. "(self hasProperty: #errorOnDraw) ifTrue: Later make this come up only when needed." { 'start drawing again' . { #myWorld . #resumeAfterDrawError } }. { 'start stepping again' . { #myWorld . #resumeAfterStepError } }. nil. { 'call #tempCommand' . { #myWorld . #tempCommand } }. { 'define #tempCommand' . { #myWorld . #defineTempCommand } }. }. self haltOnceEnabled ifTrue: [menu add: 'disable halt/inspect once' translated target: menu action: #clearHaltOnce] ifFalse: [menu add: 'enable halt/inspect once' translated target: menu action: #setHaltOnce]. ^menu ! ! !TheWorldMenu methodsFor: '*Tools' stamp: 'jmv 3/4/2009 10:43'! startThenBrowseMessageTally "Tally only the UI process" (self confirm: 'MessageTally the UI process until the mouse pointer goes to the top of the screen') ifTrue: [TimeProfileBrowser onBlock: [[Sensor peekMousePt y > 10] whileTrue: [World doOneCycle]]]! ! MessageTally initialize! Magnitude subclass: #MessageTally instanceVariableNames: 'class method process tally receivers senders time gcStats maxClassNameSize maxClassPlusSelectorSize maxTabs' classVariableNames: 'DefaultPollPeriod ShowProcesses Timer' poolDictionaries: '' category: 'System-Tools'! |
In reply to this post by Andreas.Raab
On Tue, Mar 3, 2009 at 6:25 PM, Andreas Raab <[hidden email]> wrote: Igor Stasenko wrote: Wikis are like gardens. Untended they grow like weeds. Unless one has a writership with an active minority of editors, who spend time trying to reorganize the wiki as it sprawls one may well end up with something effectively unusable. But as a form for organizing growing reference material IMO they can't be beat; look at Wikipedia. That is a superb wiki. The VisualWorks wiki was pretty good until its lack of spam protection and lack of long-term hosting killed it dead. Couldn't we have a community project to reorganize the wiki? Its the right form, its just a little overgrown right now.
Should we replace the damn thing with a community blog instead? Different form for different uses. The Squeak daily news works as a blog. I can't see how a blog would scale to hold the reference material for Galaxy Squeak.
I think this might be a better way of dealing with the information overload - you get dated, tagged entry and if we keep this open for pretty much every member of the community (using the "standard" username/password from the Swiki) we could use it much the same. |
In reply to this post by Bert Freudenberg
On planet.squeak.org, I use squeak/smalltalk-specific topic feeds when I
can find them, and I omit blogs which seem less than 50% squeak related. I usually find the result on-topic enough, with occasional enjoyable diversions to euro board games etc. My model is the Debian, Gnome and Ubuntu planets which are about building a strong community, not just propagating technical discussion. But, just send a patch or suggestion implementing the changes you want. If a particular blog is too off-topic and there's no topic feed, you could try contacting the author here and talking them into line. |
Free forum by Nabble | Edit this page |