From: Alex Twisleton-Wykeham-F. <al...@fi...> - 2006-03-08 12:32:16
|
All, following on from my earlier optimising of Thread shutdowns inside webmacro, I've been doing a bit of actual CPU profiling of the running application and I found that a significant percentage of processor time was spent creating new FastWriter objects as part of the Template.evaluateAsBytes(String,Context) method invoked from the IncludeDirective.write(FastWriter,Context). I couldn't see any reason why you should need to create a new FastWriter just to write the template into it, convert it to a byte array and then write it into the outer FastWriter - especially as the inner FastWriter is only used for the duration of the evaluateAsBytes method and is initialised using the same encoding as the outer FastWriter. I therefore made the following changes as an experiment:- Added:- public interface Template { public void write(FastWriter out, Context context) throws PropertyException, IOException; } changed:- public class IncludeDirective { public void write(FastWriter out, Context context) throws PropertyExcception, IOException { <snip> case TYPE_TEMPLATE: out.write(((Template) toInclude).evaluateAsBytes(out.getEncoding(), context)); <snip> } } to:- public class IncludeDirective { public void write(FastWriter out, Context context) throws PropertyExcception, IOException { <snip> case TYPE_TEMPLATE: ((Template) toInclude).write(out, context); <snip> } } which has yielded a considerable performance increase in the #include approach, not to mention a much happier garbage collector (not having to allocate a char[512] every time that you include a template). Are there any major gotcha's in this approach that I haven't spotted, and is it worth trying to look through the rest of the code at FastWriter creation and try and move it more towards a "streaming" style of model with a single FastWriter passed down through the items which is written to directly rather than a tree of FastWriters that bubble up their byte[] outputs? Alex |
From: Alex Twisleton-Wykeham-F. <al...@fi...> - 2006-03-08 13:21:18
|
On Wed 8 March 2006 12:32, Alex Twisleton-Wykeham-Fiennes wrote: > All, > > following on from my earlier optimising of Thread shutdowns inside > webmacro, I've been doing a bit of actual CPU profiling of the running > application and I found that a significant percentage of processor time was > spent creating new FastWriter objects as part of the > Template.evaluateAsBytes(String,Context) method invoked from the > IncludeDirective.write(FastWriter,Context). I've found a similar situation inside the EvalDirective that was creating FastWriters for each level of Eval. Therefore a self-recursive #eval statement (such as discussed on the list recently) would generate a char[512] for every time it recursed which would all then be flattened down onto the parent one and eventually written out onto the original FastWriter. I patched this as well to pass the master FastWriter down the chain, and it does indeed give a major performance increase (assuming that your templating structure uses a fair amount of #eval) (summary of patch at end of email). The only point of concern for me about this is what happens to the state of the master FastWriter if the process fails at some point down the line. In the default model, the PropertyException is thrown and the content of the FastWriter is not required and an error template is returned. However, there may be situations when the PropertyException is caught and handled differently. In this case, the master FastWriter would contain data up to the point when the PropertyException was thrown, whereas the previous model would contain data up to the start of the block which triggered the PropertyException. Would this be a problem for anyone if it changed in this way? Alex ------------------------------------------------------------ Changes to EvalDirective:- public void write(org.webmacro.FastWriter out, org.webmacro.Context context) throws org.webmacro.PropertyException, java.io.IOException { try { // removed this as no longer necessary... // String s = null; Context c = null; Macro macro = (Macro)_evalTarget.getValue(context); if (_mapExpr == null) { // no map specified, use current context // shift to write directly to master FastWriter:- // (String)macro.evaluate(context); macro.write(out, context); } else { // <SNIP> // shift to writ directly to master FastWriter // s = (String)macro.evaluate(c); macro.write(out, c); } // removed this as no longer necessary... // out.write(s); } catch (Exception e) { if (e instanceof PropertyException) throw (PropertyException)e; throw new PropertyException("#eval: Unable to evaluate macro.", e); } } |
From: Eric B. R. <eb...@tc...> - 2006-03-08 17:58:50
|
I've been thinking back to when I write IncludeDirective and I simply cannot remember why it makes a new FastWriter. Was it because the old ParseDirective did that and I was just coping it? Was it out of sheer stupidity? Or maybe some reason about not wanting to muck with the real FastWriter in the event of a parsing/evaluation exception. I dunno. At any rate, I can't think of a reason why your idea won't work. So I say go for it. Go for the #eval thing too. I know #setblock uses the same pattern, but it might actually be necessary for #setblock to do this. eric On Mar 8, 2006, at 7:32 AM, Alex Twisleton-Wykeham-Fiennes wrote: > All, > > following on from my earlier optimising of Thread shutdowns inside > webmacro, > I've been doing a bit of actual CPU profiling of the running > application and > I found that a significant percentage of processor time was spent > creating > new FastWriter objects as part of the > Template.evaluateAsBytes(String,Context) method invoked from the > IncludeDirective.write(FastWriter,Context). > > I couldn't see any reason why you should need to create a new > FastWriter just > to write the template into it, convert it to a byte array and then > write it > into the outer FastWriter - especially as the inner FastWriter is > only used > for the duration of the evaluateAsBytes method and is initialised > using the > same encoding as the outer FastWriter. > > I therefore made the following changes as an experiment:- > > Added:- > public interface Template { > public void write(FastWriter out, Context context) > throws PropertyException, IOException; > } > > changed:- > public class IncludeDirective { > public void write(FastWriter out, Context context) > throws PropertyExcception, IOException > { > <snip> > case TYPE_TEMPLATE: > out.write(((Template) toInclude).evaluateAsBytes > (out.getEncoding(), > context)); > <snip> > } > } > to:- > public class IncludeDirective { > public void write(FastWriter out, Context context) > throws PropertyExcception, IOException > { > <snip> > case TYPE_TEMPLATE: > ((Template) toInclude).write(out, context); > <snip> > } > } > > > which has yielded a considerable performance increase in the #include > approach, not to mention a much happier garbage collector (not > having to > allocate a char[512] every time that you include a template). > > Are there any major gotcha's in this approach that I haven't > spotted, and is > it worth trying to look through the rest of the code at FastWriter > creation > and try and move it more towards a "streaming" style of model with > a single > FastWriter passed down through the items which is written to > directly rather > than a tree of FastWriters that bubble up their byte[] outputs? > > Alex > > > ------------------------------------------------------- > This SF.Net email is sponsored by xPML, a groundbreaking scripting > language > that extends applications into web and mobile media. Attend the > live webcast > and join the prime developer group breaking into this new coding > territory! > http://sel.as-us.falkag.net/sel? > cmd=lnk&kid=110944&bid=241720&dat=121642 > _______________________________________________ > Webmacro-user mailing list > Web...@li... > https://lists.sourceforge.net/lists/listinfo/webmacro-user |
From: Alex Twisleton-Wykeham-F. <al...@fi...> - 2006-03-08 18:13:21
|
On Wed 8 March 2006 17:58, Eric B. Ridge wrote: > I've been thinking back to when I write IncludeDirective and I simply > cannot remember why it makes a new FastWriter. Was it because the > old ParseDirective did that and I was just coping it? Was it out of > sheer stupidity? Or maybe some reason about not wanting to muck with > the real FastWriter in the event of a parsing/evaluation exception. > I dunno. The only reason for the exception handling being an issue would be if you were going to be doing some kind of intelligent rollback on your nested template evaluation. However, this doesn't smell write from an encapsulation point of view as I would expect any calculations that had rollbacks would take place in java space before you handed over control to the webmacro template, but if anyone has any real world situations that this would break then let me know. > At any rate, I can't think of a reason why your idea won't work. So > I say go for it. OK. I'll get the destroy() stuff out of the way first and then have a closer look at the whole streaming thing... > Go for the #eval thing too. I know #setblock uses the same pattern, > but it might actually be necessary for #setblock to do this. I think that it is probably worth it. On a relatively trivial application that was doing a fair amount of nested including and evaluating of templates, OptimizeIt was reporting that roughly 10 - 15 % of time was spent purely in creating FastWriters which just feels wrong to me... I'll have a sweep through the entire tree looking for the usage patterns of FastWriter and will see if there are any other points that look like they should be tweaked as well. Alex |
From: <Web...@St...> - 2006-03-09 17:00:25
|
On Wed, 8 Mar 2006, Eric B. Ridge wrote: | I've been thinking back to when I write IncludeDirective and I simply cannot | remember why it makes a new FastWriter. Was it because the old ParseDirective | did that and I was just coping it? Was it out of sheer stupidity? Or maybe | some reason about not wanting to muck with the real FastWriter in the event of | a parsing/evaluation exception. I dunno. You should have commented it in the code. .. One comment about the FastWriter/Writer thingy: A "resetable" writer would be fantastic, preferrably having unlimited resetable space (just growing adding byte-arrays into some list as needed). I am responsible for a portal, which renders every portlet in its own context and with its own "StringWriter", so that if it throws an exception, I can throw it away, and instead render an error-portlet. If all goes well, I commit the fully rendered portlet to the FastWriter, and move along. However, this would be hugely better if I could just _always_ pass along the same fastwriter recursing down includes and macros and whatnots. Before I venture into the next portlet, i do a mark(). Then I let it render the portlet, with its recursing. Then if an exception turns up, I'll just do a reset(), and then output an error-template instead, while if it goes well, i'll do a _flush()_ to commit the stuff all the way to the browser at the other end of the stream (I feel this should be up to me, the webapp writer, to decide when to flush). That would have been absolutely great, and absolutely more performant. Regards, Endre. |
From: Alex Twisleton-Wykeham-F. <al...@fi...> - 2006-03-09 18:27:43
|
On Thu 9 March 2006 17:00, Endre St=F8lsvik wrote: > On Wed, 8 Mar 2006, Eric B. Ridge wrote: > | I've been thinking back to when I write IncludeDirective and I simply > | cannot remember why it makes a new FastWriter. Was it because the old > | ParseDirective did that and I was just coping it? Was it out of sheer > | stupidity? Or maybe some reason about not wanting to muck with the real > | FastWriter in the event of a parsing/evaluation exception. I dunno. > > You should have commented it in the code. > > .. > > One comment about the FastWriter/Writer thingy: A "resetable" writer would > be fantastic, preferrably having unlimited resetable space (just growing > adding byte-arrays into some list as needed). > I am responsible for a portal, which renders every portlet in its own > context and with its own "StringWriter", so that if it throws an > exception, I can throw it away, and instead render an error-portlet. If > all goes well, I commit the fully rendered portlet to the FastWriter, and > move along. > > However, this would be hugely better if I could just _always_ pass along > the same fastwriter recursing down includes and macros and whatnots. > Before I venture into the next portlet, i do a mark(). Then I let it > render the portlet, with its recursing. Then if an exception turns up, > I'll just do a reset(), and then output an error-template instead, while > if it goes well, i'll do a _flush()_ to commit the stuff all the way to > the browser at the other end of the stream (I feel this should be up to > me, the webapp writer, to decide when to flush). That would have been > absolutely great, and absolutely more performant. It's not going to be extending FastWriter because after a cursory look at t= he=20 code it appears to be caching small (<4k blocks) of binary data in the=20 =46astWriter and then pushing them out to the underlying OutputStream whene= ver=20 it needs to get it's internal buffer into some kind of known state. Therefore if it had already pushed data out to the OutputStream when you tr= ied=20 to rollback your code to the last point then it would fail because it would= =20 no longer have access to or control of the data. To do this properly you would need to maintain a single data structure that= =20 holds the entire contents of whatever is written to it in memory and then=20 shifts it out once you've satisfied yourself that it isn't going to need to= =20 rollback. I don't think that you are going to do this by extending FastWriter - it ju= st=20 doesn't feel right. Unfortunately great chunks of WebMacro are expecting=20 =46astWriter as their target output stream so at present you are kind of=20 stumped. Might be interesting to look at what the difference is between=20 Writer and FastWriter and refactor the calling code if it is not too much=20 hassle? However, the more I think about it, the more I feel that this "rolling back= "=20 is not a nice idea, for the following reasons:- =2D the success / failure thing should be a javaspace thing and to only hav= e it=20 occur inside the middle of a portlet feels a bit odd to me. I kind of feel= =20 that when the portlet rendering template is invoked, that the context shoul= d=20 already contain a set of calculated portlets (or error portlets) that refle= ct=20 the state of the system. Then the rollback is just not necessary. =2D rolling back the output is only half of the problem. webmacro code can= make=20 changes to the state of the backend java system and to the state of the=20 context. Just because you roll the output stream back doesn't mean that th= e=20 java and context are in any way in a consistent state with what they were=20 before the rollback point. To imply that they are is just tempting fate... Just out of interest - how were you envisioning this rolling back happening= ? =20 Was it going to be a java space action or would it take place during the=20 template rendering phase? Alex |
From: Keats K. <ke...@xa...> - 2006-03-09 23:11:03
|
If my memory serves (which is dubious) the FastWriter caches an entire page before flushing to the output stream. This was a controversial design decision -- there were a lot of complaints about potential performance impacts, but no metrics that I'm aware of. At one point I developed a #flush directive to work around this for a particular application. In any case, if I'm correct, it should be a simple matter to do the sort of checkpoint/rollback mechanism that is being discussed. But I'm not sure this is a good idea. It would be adding more dependencies on the FastWriter and it seems like an overly complex error handling architecture. We already have the pluggable EEH mechanism which seems pretty adequate. Generally the error "culture" in WM is, if you anticipate errors, handle them in code. Unanticipated errors should result in an error template being rendered. I think the bigger issue is with the FastWriter mechanism as a whole. It should be an interface so that you can plug in an implementation that serves your needs. This is much more in line with the flexibility that permeates nearly every other aspect of WM. My 2p. Keats Alex Twisleton-Wykeham-Fiennes wrote: >On Thu 9 March 2006 17:00, Endre Stølsvik wrote: > > >>On Wed, 8 Mar 2006, Eric B. Ridge wrote: >>| I've been thinking back to when I write IncludeDirective and I simply >>| cannot remember why it makes a new FastWriter. Was it because the old >>| ParseDirective did that and I was just coping it? Was it out of sheer >>| stupidity? Or maybe some reason about not wanting to muck with the real >>| FastWriter in the event of a parsing/evaluation exception. I dunno. >> >>You should have commented it in the code. >> >>.. >> >>One comment about the FastWriter/Writer thingy: A "resetable" writer would >>be fantastic, preferrably having unlimited resetable space (just growing >>adding byte-arrays into some list as needed). >> I am responsible for a portal, which renders every portlet in its own >>context and with its own "StringWriter", so that if it throws an >>exception, I can throw it away, and instead render an error-portlet. If >>all goes well, I commit the fully rendered portlet to the FastWriter, and >>move along. >> >>However, this would be hugely better if I could just _always_ pass along >>the same fastwriter recursing down includes and macros and whatnots. >>Before I venture into the next portlet, i do a mark(). Then I let it >>render the portlet, with its recursing. Then if an exception turns up, >>I'll just do a reset(), and then output an error-template instead, while >>if it goes well, i'll do a _flush()_ to commit the stuff all the way to >>the browser at the other end of the stream (I feel this should be up to >>me, the webapp writer, to decide when to flush). That would have been >>absolutely great, and absolutely more performant. >> >> > >It's not going to be extending FastWriter because after a cursory look at the >code it appears to be caching small (<4k blocks) of binary data in the >FastWriter and then pushing them out to the underlying OutputStream whenever >it needs to get it's internal buffer into some kind of known state. > >Therefore if it had already pushed data out to the OutputStream when you tried >to rollback your code to the last point then it would fail because it would >no longer have access to or control of the data. > >To do this properly you would need to maintain a single data structure that >holds the entire contents of whatever is written to it in memory and then >shifts it out once you've satisfied yourself that it isn't going to need to >rollback. > >I don't think that you are going to do this by extending FastWriter - it just >doesn't feel right. Unfortunately great chunks of WebMacro are expecting >FastWriter as their target output stream so at present you are kind of >stumped. Might be interesting to look at what the difference is between >Writer and FastWriter and refactor the calling code if it is not too much >hassle? > >However, the more I think about it, the more I feel that this "rolling back" >is not a nice idea, for the following reasons:- > >- the success / failure thing should be a javaspace thing and to only have it >occur inside the middle of a portlet feels a bit odd to me. I kind of feel >that when the portlet rendering template is invoked, that the context should >already contain a set of calculated portlets (or error portlets) that reflect >the state of the system. Then the rollback is just not necessary. > >- rolling back the output is only half of the problem. webmacro code can make >changes to the state of the backend java system and to the state of the >context. Just because you roll the output stream back doesn't mean that the >java and context are in any way in a consistent state with what they were >before the rollback point. To imply that they are is just tempting fate... > >Just out of interest - how were you envisioning this rolling back happening? >Was it going to be a java space action or would it take place during the >template rendering phase? > >Alex > > >------------------------------------------------------- >This SF.Net email is sponsored by xPML, a groundbreaking scripting language >that extends applications into web and mobile media. Attend the live webcast >and join the prime developer group breaking into this new coding territory! >http://sel.as-us.falkag.net/sel?cmd=k&kid0944&bid$1720&dat1642 >_______________________________________________ >Webmacro-user mailing list >Web...@li... >https://lists.sourceforge.net/lists/listinfo/webmacro-user > > > |
From: Alex Twisleton-Wykeham-F. <al...@fi...> - 2006-03-09 23:40:39
|
On Thu 9 March 2006 23:11, Keats Kirsch wrote: > If my memory serves (which is dubious) the FastWriter caches an entire > page before flushing to the output stream. This was a controversial > design decision -- there were a lot of complaints about potential > performance impacts, but no metrics that I'm aware of. At one point I > developed a #flush directive to work around this for a particular > application. I have a vague memory about this - wasn't it to do with the time before the= =20 first data is sent to the client that was under discussion rather than the= =20 overall system throughput? > In any case, if I'm correct, it should be a simple matter to do the sort > of checkpoint/rollback mechanism that is being discussed. =20 until someone used your #flush directive (or called flush() on the FastWrit= er=20 inside one of their own directives). Then all your assumptions about=20 rollback go out the window - you'd have to restrict access to the flush=20 method to prevent this happening... > But I'm not=20 > sure this is a good idea. It would be adding more dependencies on the > FastWriter and it seems like an overly complex error handling > architecture. We already have the pluggable EEH mechanism which seems > pretty adequate. Generally the error "culture" in WM is, if you > anticipate errors, handle them in code. Unanticipated errors should > result in an error template being rendered. > > I think the bigger issue is with the FastWriter mechanism as a whole. > It should be an interface so that you can plug in an implementation that > serves your needs. This is much more in line with the flexibility that > permeates nearly every other aspect of WM. I've just been having a quick scan through the source for which methods are= =20 used in FastWriter, and it is pretty much everything across quite a wide=20 variety of situations. If you were therefore going to make an interface fr= om=20 it then it would pretty much duplicate the structure of the current=20 =46astWriter API. What alterations would you make to the implemenation of= =20 =46astWriter if you did have an extendable structure? My feeling is that an easier to implement and probably functionally more=20 interesting approach would be to make the ByteBufferOutputStream into an=20 interface with a Factory method that gets past to the FastWriter on=20 construction. Most of the changes that I could see being useful=20 (auto-flushing to the output stream to save memory etc etc) would take plac= e=20 at this level in the code and wouldn't touch the FastWriter interface and=20 therefore wouldn't mean refactoring pretty much everything else. Alex > My 2p. > > Keats > > Alex Twisleton-Wykeham-Fiennes wrote: > >On Thu 9 March 2006 17:00, Endre St=F8lsvik wrote: > >>On Wed, 8 Mar 2006, Eric B. Ridge wrote: > >>| I've been thinking back to when I write IncludeDirective and I simply > >>| cannot remember why it makes a new FastWriter. Was it because the old > >>| ParseDirective did that and I was just coping it? Was it out of sheer > >>| stupidity? Or maybe some reason about not wanting to muck with the > >>| real FastWriter in the event of a parsing/evaluation exception. I > >>| dunno. > >> > >>You should have commented it in the code. > >> > >>.. > >> > >>One comment about the FastWriter/Writer thingy: A "resetable" writer > >> would be fantastic, preferrably having unlimited resetable space (just > >> growing adding byte-arrays into some list as needed). > >> I am responsible for a portal, which renders every portlet in its own > >>context and with its own "StringWriter", so that if it throws an > >>exception, I can throw it away, and instead render an error-portlet. If > >>all goes well, I commit the fully rendered portlet to the FastWriter, a= nd > >>move along. > >> > >>However, this would be hugely better if I could just _always_ pass along > >>the same fastwriter recursing down includes and macros and whatnots. > >>Before I venture into the next portlet, i do a mark(). Then I let it > >>render the portlet, with its recursing. Then if an exception turns up, > >>I'll just do a reset(), and then output an error-template instead, while > >>if it goes well, i'll do a _flush()_ to commit the stuff all the way to > >>the browser at the other end of the stream (I feel this should be up to > >>me, the webapp writer, to decide when to flush). That would have been > >>absolutely great, and absolutely more performant. > > > >It's not going to be extending FastWriter because after a cursory look at > > the code it appears to be caching small (<4k blocks) of binary data in > > the FastWriter and then pushing them out to the underlying OutputStream > > whenever it needs to get it's internal buffer into some kind of known > > state. > > > >Therefore if it had already pushed data out to the OutputStream when you > > tried to rollback your code to the last point then it would fail because > > it would no longer have access to or control of the data. > > > >To do this properly you would need to maintain a single data structure > > that holds the entire contents of whatever is written to it in memory a= nd > > then shifts it out once you've satisfied yourself that it isn't going to > > need to rollback. > > > >I don't think that you are going to do this by extending FastWriter - it > > just doesn't feel right. Unfortunately great chunks of WebMacro are > > expecting FastWriter as their target output stream so at present you are > > kind of stumped. Might be interesting to look at what the difference is > > between Writer and FastWriter and refactor the calling code if it is not > > too much hassle? > > > >However, the more I think about it, the more I feel that this "rolling > > back" is not a nice idea, for the following reasons:- > > > >- the success / failure thing should be a javaspace thing and to only ha= ve > > it occur inside the middle of a portlet feels a bit odd to me. I kind = of > > feel that when the portlet rendering template is invoked, that the > > context should already contain a set of calculated portlets (or error > > portlets) that reflect the state of the system. Then the rollback is > > just not necessary. > > > >- rolling back the output is only half of the problem. webmacro code can > > make changes to the state of the backend java system and to the state of > > the context. Just because you roll the output stream back doesn't mean > > that the java and context are in any way in a consistent state with what > > they were before the rollback point. To imply that they are is just > > tempting fate... > > > >Just out of interest - how were you envisioning this rolling back > > happening? Was it going to be a java space action or would it take place > > during the template rendering phase? > > > >Alex > > > > > >------------------------------------------------------- > >This SF.Net email is sponsored by xPML, a groundbreaking scripting > > language that extends applications into web and mobile media. Attend the > > live webcast and join the prime developer group breaking into this new > > coding territory! > > http://sel.as-us.falkag.net/sel?cmd=3Dk&kid=110944&bid$1720&dat=121642 > >_______________________________________________ > >Webmacro-user mailing list > >Web...@li... > >https://lists.sourceforge.net/lists/listinfo/webmacro-user > > ------------------------------------------------------- > This SF.Net email is sponsored by xPML, a groundbreaking scripting langua= ge > that extends applications into web and mobile media. Attend the live > webcast and join the prime developer group breaking into this new coding > territory! > http://sel.as-us.falkag.net/sel?cmd=3Dlnk&kid=3D110944&bid=3D241720&dat= =3D121642 > _______________________________________________ > Webmacro-user mailing list > Web...@li... > https://lists.sourceforge.net/lists/listinfo/webmacro-user |
From: Tim P. <ti...@pa...> - 2006-03-11 18:18:18
|
On Thursday 09 March 2006 23:11, Keats Kirsch wrote: > If my memory serves (which is dubious) the FastWriter caches an entire > page before flushing to the output stream. This was a controversial > design decision -- there were a lot of complaints about potential > performance impacts, but no metrics that I'm aware of. At one point I > developed a #flush directive to work around this for a particular > application. > Yes, Lane and I gave up on trying to reintroduce the lost functionality in Melati. It is still missed. If you are trying to paginate a book this is a process that might take fifteen or more minutes, so the status page needs to be updated every page or chapter to keep the browser believing something is happening. Really nice to see some activity on WM. Cheers tim pizey -- Registered linux user #21337, http://counter.li.org. |
From: <Web...@St...> - 2006-03-13 12:30:22
|
| | Just out of interest - how were you envisioning this rolling back happening? | Was it going to be a java space action or would it take place during the | template rendering phase? I already do this, dude - so all your arguments about why it ain't smart is simply not applicable. The clue is that this is a _portlet engine_, right? Every portlet operates on its own, and you may view the portal as an operating system with the portlets as applications. If you understand this view, then I guess you understand why containment of errors are both smart and correct, and the "internal state change" arguments are simply not interesting (Better to contain _one_ error than make it propagate all the way out to the users browser, so that he potentially can't see the portal page at all (due to messed up nesting of tables etc)). I do it using _a new_ FastWriter with a temporary backing, then if everything went right, I put the result to the FastWriter. This temporary backing paradigm obviously isn't the best, and a mark/reset/flush paradigm would be much better for my part. Regards, Endre. |
From: Alex Twisleton-Wykeham-F. <al...@fi...> - 2006-03-13 13:19:12
|
On Mon 13 March 2006 12:30, Endre St=F8lsvik wrote: > | Just out of interest - how were you envisioning this rolling back > | happening? Was it going to be a java space action or would it take place > | during the template rendering phase? > > I already do this, dude - so all your arguments about why it ain't smart > is simply not applicable. > > The clue is that this is a _portlet engine_, right? Every portlet operates > on its own, and you may view the portal as an operating system with the > portlets as applications. If you understand this view, then I guess you > understand why containment of errors are both smart and correct, and the > "internal state change" arguments are simply not interesting (Better to > contain _one_ error than make it propagate all the way out to the users > browser, so that he potentially can't see the portal page at all (due to > messed up nesting of tables etc)). > > I do it using _a new_ FastWriter with a temporary backing, then if > everything went right, I put the result to the FastWriter. Do you use a seperate Context for each portlet as well? If the portlet fai= ls,=20 then how do you roll the Context back to the state that it was in at the=20 beginning of the evalaution of the portlet? > This temporary backing paradigm obviously isn't the best, and a > mark/reset/flush paradigm would be much better for my part. I can see where you are coming from on this, but it is very hard to state w= hat=20 the side effects of flushing the FastWriter early and / or rolling it back = to=20 an earlier state. I think that any such mechanism would need to be=20 integrated with the same ability on the Context that was being used as well= =20 for it to be safe. Either way, I'm trying not to create any functional changes to the code as = a=20 whole at present unless it is really broken as I am not up to speed enough = on=20 the internal architecture to state what the effect of the changes might be = so=20 I suspect that I'm not going to look at this just now. However, my gut reaction from the profiling that I've done suggests that if= =20 what you are after is maximum performance from your system then the best wa= y=20 of evaluating your portlets would be:- #foreach $portlet in $portlets { #include as template "$portlet.prepareView" } where the $portlet.prepareView prepares all the necessary state information= =20 associated with the current view. If this all goes smoothly in javaspace=20 then it returns the path to the standard view of the portlet, otherwise it= =20 returns the path to the error template. of course you can still get an error while rendering your standard view, bu= t=20 if all of the classes and methods that you are exposing to the template are= =20 purely read only (ie the template is just a view rather than the controller= )=20 then the performance increase that you get from not scripting the work up i= n=20 webmacro will be greater than the performance increase that you would get b= y=20 not generating a new FastWriter for each portlet. =20 WebMacro is great and quite surprisingly fast, but it isn't by definition a= s=20 fast as doing the same thing in direct java code, so the less processing wo= rk=20 that you perform inside the template, the better the ultimate performance=20 would be. I would highly recommend getting hold of a copy of OptimizeIt and actually= =20 benchmarking the performance of your portlet application before embarking o= n=20 refactoring the FastWriter in such a manner. Alex |
From: <Web...@St...> - 2006-03-17 11:23:52
|
On Mon, 13 Mar 2006, Alex Twisleton-Wykeham-Fiennes wrote: | > | > I do it using _a new_ FastWriter with a temporary backing, then if | > everything went right, I put the result to the FastWriter. | | Do you use a seperate Context for each portlet as well? Yes. But assuming that the Portlets aren't _pure_ evil, this would have been a big thing: I could just have recreated the initial state before each rendering, by using a "weird-long-named" context-var for "my state", hoping that the corelet wouldn't intentially mess things up. But I do make a new Context, due to this concern. | | > This temporary backing paradigm obviously isn't the best, and a | > mark/reset/flush paradigm would be much better for my part. | | I can see where you are coming from on this, but it is very hard to state what | the side effects of flushing the FastWriter early and / or rolling it back to | an earlier state. Why is that? This seems completely illogical to me, I can't see at all where you're coming from. If I still make new Contexts, and you understand that each portlet is "on its own" (with a logical separate context too), and if I don't commit bytes to the browser-stream before flush, then "rolling back" is _exactly_ the same as ditching the buffer, _as I do now_. | I think that any such mechanism would need to be integrated with the | same ability on the Context that was being used as well for it to be | safe. Make a new one?! .. or as suggested above. | | However, my gut reaction from the profiling that I've done suggests that if | what you are after is maximum performance from your system then the best way | of evaluating your portlets would be:- | | #foreach $portlet in $portlets { | #include as template "$portlet.prepareView" | } Of course - which can't contain errors. | | where the $portlet.prepareView prepares all the necessary state information | associated with the current view. If this all goes smoothly in javaspace | then it returns the path to the standard view of the portlet, otherwise it | returns the path to the error template. People don't program fantastic code. Suddenly, some method returns null. Suddenly, some seldom-used if-case kicks in, and everything goes haywire. I really can't understand why my needs are so non-understandable?! I am not constructing some obscure use-case here: This "damage control" is what I do now, I'd just like to have a more optimized way of doing it using the features that actually are present in the fastwriter already. | | I would highly recommend getting hold of a copy of OptimizeIt and actually | benchmarking the performance of your portlet application before embarking on | refactoring the FastWriter in such a manner. I use JProfiler, but thanks for the tip. Endre |
From: Alex Twisleton-Wykeham-F. <al...@fi...> - 2006-03-17 11:51:33
|
On Fri 17 March 2006 11:23, Endre St=F8lsvik wrote: > On Mon, 13 Mar 2006, Alex Twisleton-Wykeham-Fiennes wrote: > | > I do it using _a new_ FastWriter with a temporary backing, then if > | > everything went right, I put the result to the FastWriter. > | > | Do you use a seperate Context for each portlet as well? > > Yes. > But assuming that the Portlets aren't _pure_ evil, this would have been a > big thing: I could just have recreated the initial state before each > rendering, by using a "weird-long-named" context-var for "my state", > hoping that the corelet wouldn't intentially mess things up. > > But I do make a new Context, due to this concern. > > | > This temporary backing paradigm obviously isn't the best, and a > | > mark/reset/flush paradigm would be much better for my part. > | > | I can see where you are coming from on this, but it is very hard to sta= te > | what the side effects of flushing the FastWriter early and / or rolling > | it back to an earlier state. > > Why is that? This seems completely illogical to me, I can't see at all > where you're coming from. > > If I still make new Contexts, and you understand that each portlet is "on > its own" (with a logical separate context too), and if I don't commit > bytes to the browser-stream before flush, then "rolling back" is _exactly_ > the same as ditching the buffer, _as I do now_. I understand exactly what you have at the moment, and I understand what is= =20 being suggested, but let me just recap for a moment:- =2D you have a series of portlets. Currently you are rendering these by=20 creating a new Context and a new FastWriter, doing all the work and then=20 dropping the contents of the FastWriter (which will either contain your=20 portlet or your error report) into the master FastWriter. =2D you are proposing to save the creation time of a new FastWriter by usin= g the=20 master FastWriter for the global template page and resetting it as necessar= y=20 to handle the consequences (I think the use of flush in your mark/reset/flu= sh=20 is maybe what is confusing because flushing by definition drops the content= s=20 of the FastWriter out to the output stream which is probably not what you=20 mean). Now, just for a moment in order to play devils advocate: supposing that we= do=20 have this #flush command that Keats mentioned, and suppose one of your=20 portlet implementors executes #flush inside one of your portlet and the byt= es=20 (both before and after your mark) are flushed out to the output stream. Yo= u=20 then try and do a reset, but the reset point along with all the data before= =20 and after it has already been sent down-stream. Personally, I think that you already have a nicely encapsulated safe struct= ure=20 for your portlets with a dedicated Context and a dedicated FastWriter for=20 each portlet. Error failure is encapsulated and you don't drop the result = of=20 your parsing / error catching out to your master FastWriter until it is=20 completed. If you are concerned about the overhead of generating lots (1 p= er=20 portlet) of new FastWriter instances, then I would use just one FastWriter= =20 that is shared between all of your Portlets, and your sequence would be:- =2D create Portlet FastWriter =2D foreach portlet in portlets - create new Portlet Context - reset Portlet FastWriter try { - render portlet with Portlet Context to Portlet FastWriter } catch (exception) { - reset FastWriter - render error with Portlet Context to Portlet FastWriter } - write Portlet FastWriter to Servlet FastWriter } =2D write Servlet FastWriter to OutputStream Now, you still have all of your encapsulation, your rollbacks work, you are= =20 creating at most one FastWriter beyond where you are, and it really doesn't= =20 matter what happens inside the rendering loop and you don't need to make an= y=20 functional changes to how the FastWriter works. Or am I missing something? (you should also look at the overhead of Context initialisation - HashMap a= nd=20 ConcurrentHashMap usage are by far the greatest CPU hogs in my tree at=20 present) <snip> Alex |
From: <Web...@St...> - 2006-03-20 13:47:45
|
On Fri, 17 Mar 2006, Alex Twisleton-Wykeham-Fiennes wrote: | On Fri 17 March 2006 11:23, Endre St=F8lsvik wrote: | > On Mon, 13 Mar 2006, Alex Twisleton-Wykeham-Fiennes wrote: | > | > I do it using _a new_ FastWriter with a temporary backing, then i= f | > | > everything went right, I put the result to the FastWriter. | > | | > | Do you use a seperate Context for each portlet as well? | > | > Yes. | > But assuming that the Portlets aren't _pure_ evil, this would have be= en a | > big thing: I could just have recreated the initial state before each | > rendering, by using a "weird-long-named" context-var for "my state", | > hoping that the corelet wouldn't intentially mess things up. | > | > But I do make a new Context, due to this concern. | > | > | > This temporary backing paradigm obviously isn't the best, and a | > | > mark/reset/flush paradigm would be much better for my part. | > | | > | I can see where you are coming from on this, but it is very hard to= state | > | what the side effects of flushing the FastWriter early and / or rol= ling | > | it back to an earlier state. | > | > Why is that? This seems completely illogical to me, I can't see at al= l | > where you're coming from. | > | > If I still make new Contexts, and you understand that each portlet is= "on | > its own" (with a logical separate context too), and if I don't commit | > bytes to the browser-stream before flush, then "rolling back" is _exa= ctly_ | > the same as ditching the buffer, _as I do now_. |=20 | I understand exactly what you have at the moment, and I understand what= is=20 | being suggested, but let me just recap for a moment:- |=20 | - you have a series of portlets. Currently you are rendering these by=20 | creating a new Context and a new FastWriter, doing all the work and the= n=20 | dropping the contents of the FastWriter (which will either contain your= =20 | portlet or your error report) into the master FastWriter. No, it doesn't contain the error-report. If it fails, I drop the=20 fastwriter, and then actually make another one, which I run the=20 error-template in, and use that (but I could have just dropped it, and=20 rendered the error-template "directly"). |=20 | - you are proposing to save the creation time of a new FastWriter by us= ing the=20 | master FastWriter for the global template page and resetting it as nece= ssary=20 | to handle the consequences (I think the use of flush in your mark/reset= /flush=20 | is maybe what is confusing because flushing by definition drops the con= tents=20 | of the FastWriter out to the output stream which is probably not what y= ou=20 | mean). Flush if it went Okay (as stated repeatedly, I believe?). That way, the=20 user would get the portlets rendered in their browser as they were=20 finished, giving an impression of something happening, even if some stupi= d=20 portlet later in the line use too much time. Rollback ("reset") if it didn't, and then render the error-template, and=20 then flush. |=20 | Now, just for a moment in order to play devils advocate: supposing tha= t we do=20 | have this #flush command that Keats mentioned, and suppose one of your=20 | portlet implementors executes #flush inside one of your portlet and the= bytes=20 | (both before and after your mark) are flushed out to the output stream.= You=20 | then try and do a reset, but the reset point along with all the data be= fore=20 | and after it has already been sent down-stream. Why whould i let the user do #flush? FastWriter.flush() would be good enough for me - I'M THE PORTAL! The _working_ trio mark(), reset() and flush() is what I'm requesting. In _production_ environments, where one is very sure about the quality of= =20 portlets, one could potentially let the #flush actually map to the=20 .flush(), instead of just noop'ing. |=20 | Personally, I think that you already have a nicely encapsulated safe st= ructure=20 | for your portlets with a dedicated Context and a dedicated FastWriter f= or=20 | each portlet. Me too thinks so! But there is way to much byte-arrays around, and if=20 things goes OK (no errors to wrap), then there is _lots_ of byte-copying=20 that is totally utterly useless. Do you see this point? I'm not quite sure how the byte-arrays work now, after your fixups (whose= =20 bugs seem _amazing_ that have been around so long!) - are they still=20 recycled? See, object creation is rather cheap these days, but it is still faster t= o=20 _not_ create objects. And byte-array copies do take _some_ time, most probably unnecessary. | Error failure is encapsulated and you don't drop the result of your=20 | parsing / error catching out to your master FastWriter until it is=20 | completed. If you are concerned about the overhead of generating lots=20 | (1 per portlet) of new FastWriter instances, then I would use just one=20 | FastWriter that is shared between all of your Portlets, and your=20 | sequence would be:- |=20 | - create Portlet FastWriter | - foreach portlet in portlets | - create new Portlet Context | - reset Portlet FastWriter | try { | - render portlet with Portlet Context to Portlet FastWriter | } catch (exception) { | - reset FastWriter | - render error with Portlet Context to Portlet FastWriter | } | - write Portlet FastWriter to Servlet FastWriter | } | - write Servlet FastWriter to OutputStream Actually that's what I _believed_ that it did already, due to the=20 pooling/recycling. I still use WM 1.1, so I guess that still holds true? But btw, isn't the FastWriter thing holding some interal state? |=20 | Now, you still have all of your encapsulation, your rollbacks work, you= are=20 | creating at most one FastWriter beyond where you are, and it really doe= sn't=20 | matter what happens inside the rendering loop and you don't need to mak= e any=20 | functional changes to how the FastWriter works. Or am I missing someth= ing? You're missing copying of bytes. |=20 | (you should also look at the overhead of Context initialisation - HashM= ap and=20 | ConcurrentHashMap usage are by far the greatest CPU hogs in my tree at=20 | present) I have my own special Context that have a "lookaside hashmap" that holds=20 the "portal context" (as opposed to "portlet context"), so that the=20 creation of context shouldn't be very heavy. Thanks for hanging in on this discussion! Regards, Endre. |