Tom,

> I know I also came in late into this thread. I would like to say I am very
> excited about the possibilities of FOP in the future and the already
> realized gains FOP gives. My overall grasp of FOP at this moment is still
> limited but I have been delving into the code and using it for a current
> project for the past 2 months. In no way am I trying to be insulting to
> anyone. I realize everyone here is very well versed in various areas of
> programming. Performance has always been an interest to me in general so I
> enjoy these types of topics. I don't mind being proven wrong.
> 
> Yes. You are correct on your assumptions based on your code.
> 
> Maybe I should have been more clear and read the initial beginning to this
> thread but I would like to clear two points up, my apologies.
> 
> I was trying to refer to two seperate issues that were being discussed,
> more so to what happens during runtime then compile time.
> 
> The first point was what the String and StringBuffer java code looks in the
> pcode. String does do concantenation with the concat method and
> StringBuffer with append?.
> 
> It does do that except under certain conditions.
> 
> So, what are the conditions under the + operator?
> 
> -If there is a chain of anonymous strings being initialized to a variable a
> LOAD happens.
> -If there is 1 reference to a String at the head or end of a chain of
> anonymous Strings a String.concat happens
> -If there are only 2 references to a String(s) being "concantenated using +
> operator" a String.concat happens
> -If the chain contains 2 or more anonymous strings seperated by at least 1
> reference to a String StringBuffer.append happens
> -If the chain contains 3 or more references to a String(s)
> StringBuffer.append happens
> -If the chain contains at least 2 references to a String(s) and at least 1
> anonymous String StringBuffer.append happens
> 
> What are the conditions for += operator?
> 
> -They are the same as above except for the additional concantenation that
> happens implicitly to the variable adding to itself.

> So to the statement that StringBuffer.append happens in "String addition"
> is only partly true given String.concat happens in a subset of the cases.

Great stuff. I hadn't done tests with two Strings and I think that the
scenarios you provide us with are great.

<snip />

When I looked at the generated pcode I couldn't understand why there
where so many (any) valueOf operations, so I regenerated the code using
1.4.1, and guess what ... it's very different. Sun have made some
considerable leeps forward in String handling.

Method void concatTests()
   0 ldc #12 <String "foo">
   2 astore_1
   3 new #2 <Class java.lang.StringBuffer>
   6 dup
   7 invokespecial #3 <Method java.lang.StringBuffer()>
  10 aload_1
  11 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
  14 ldc #13 <String "bar">
  16 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
  19 invokevirtual #10 <Method java.lang.String toString()>
  22 astore_1
  23 ldc #14 <String "sofarsogood">
  25 astore_2
  26 new #2 <Class java.lang.StringBuffer>
  29 dup
  30 invokespecial #3 <Method java.lang.StringBuffer()>
  33 ldc #15 <String "boofar">
  35 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
  38 aload_1
  39 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
  42 invokevirtual #10 <Method java.lang.String toString()>
  45 astore_3
  46 new #2 <Class java.lang.StringBuffer>
  49 dup
  50 invokespecial #3 <Method java.lang.StringBuffer()>
  53 aload_2
  54 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
  57 aload_3
  58 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
  61 invokevirtual #10 <Method java.lang.String toString()>
  64 astore 4
  66 new #2 <Class java.lang.StringBuffer>
  69 dup
  70 invokespecial #3 <Method java.lang.StringBuffer()>
  73 aload_1
  74 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
  77 aload_2
  78 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
  81 aload_3
  82 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
  85 invokevirtual #10 <Method java.lang.String toString()>
  88 astore 5
  90 new #2 <Class java.lang.StringBuffer>
  93 dup
  94 invokespecial #3 <Method java.lang.StringBuffer()>
  97 aload_0
  98 ldc #16 <String "goo">
 100 invokespecial #7 <Method java.lang.String
makeString(java.lang.String)>
 103 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
 106 aload_0
 107 ldc #13 <String "bar">
 109 invokespecial #7 <Method java.lang.String
makeString(java.lang.String)>
 112 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
 115 invokevirtual #10 <Method java.lang.String toString()>
 118 astore 6
 120 new #2 <Class java.lang.StringBuffer>
 123 dup
 124 invokespecial #3 <Method java.lang.StringBuffer()>
 127 ldc #17 <String "boo">
 129 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
 132 aload_1
 133 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
 136 ldc #18 <String "far">
 138 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
 141 invokevirtual #10 <Method java.lang.String toString()>
 144 astore 7
 146 new #2 <Class java.lang.StringBuffer>
 149 dup
 150 invokespecial #3 <Method java.lang.StringBuffer()>
 153 aload 4
 155 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
 158 aload 5
 160 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
 163 aload 6
 165 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
 168 invokevirtual #10 <Method java.lang.String toString()>
 171 astore 4
 173 new #2 <Class java.lang.StringBuffer>
 176 dup
 177 invokespecial #3 <Method java.lang.StringBuffer()>
 180 aload 4
 182 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
 185 ldc #19 <String "foobarfoo">
 187 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
 190 invokevirtual #10 <Method java.lang.String toString()>
 193 astore 4
 195 new #2 <Class java.lang.StringBuffer>
 198 dup
 199 invokespecial #3 <Method java.lang.StringBuffer()>
 202 aload 4
 204 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
 207 ldc #20 <String "boobar">
 209 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
 212 aload 5
 214 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
 217 invokevirtual #10 <Method java.lang.String toString()>
 220 astore 4
 222 new #2 <Class java.lang.StringBuffer>
 225 dup
 226 invokespecial #3 <Method java.lang.StringBuffer()>
 229 aload 4
 231 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
 234 ldc #17 <String "boo">
 236 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
 239 aload 5
 241 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
 244 ldc #13 <String "bar">
 246 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
 249 invokevirtual #10 <Method java.lang.String toString()>
 252 astore 4
 254 new #2 <Class java.lang.StringBuffer>
 257 dup
 258 invokespecial #3 <Method java.lang.StringBuffer()>
 261 aload_2
 262 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
 265 aload_2
 266 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
 269 invokevirtual #10 <Method java.lang.String toString()>
 272 astore 8
 274 new #2 <Class java.lang.StringBuffer>
 277 dup
 278 invokespecial #3 <Method java.lang.StringBuffer()>
 281 aload_2
 282 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
 285 aload_3
 286 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
 289 ldc #21 <String "end">
 291 invokevirtual #5 <Method java.lang.StringBuffer
append(java.lang.String)>
 294 invokevirtual #10 <Method java.lang.String toString()>
 297 astore 9
 299 return

Which goes further to my argument of leaving it to the compiler.

> The point that is more interesting is what happens during runtime and
> that's what I was trying to emphasize, poorly.
> 
> The question is how many String objects are being handled by the JVM in
> memory, how often garbage collection happens, and at what cost? I have not
> timed your examples but I believe what you stated. I have run similar tests
> but from a different angle. The only difference between tests was that they
> were controlled within a loop. The times were different. The reason I did
> this is to see how much memory and time is spent within the scope of each
> method.
> 
> The testStringAppendloop was exponentially faster with testStringAddloop
> coming in second and third for testStringIncrementloop. The times of course
> will differ on different platforms and cpu's but I list them anyway.

That's for sure. As I pointed out earlier loops are one of the places
you should consider a StringBuffer.

> This is my sample code derived from your examples; byte-code following.
> 1.4.0_01-b03
> 
> times with 3000 iterations compaq 512 mb 866ghz intel cpu:
> 16 ms testStringAppendloop
> 2000 ms testStringAddloop
> 5531 ms testStringIncrementloop
> 
> public String testStringIncrementloop(int loop)
>     {
>         String temp = "";
> 
>         for (int i=0;i<loop;i++)
>         {
>           temp += makeString("this is ");
>           temp += "a ";
>           temp += makeString("concat test");
>         }
> 
>         return temp;
> 
>     }
> 
>     public String testStringAddloop(int loop)
>     {
>         String temp = "";
> 
>         for (int i=0;i<loop;i++)
>         {
>           temp = temp + makeString("this is ") + "a " + makeString("concat
> test");
>         }
> 
>         return temp;
>     }
> 
>     public String testStringAppendloop(int loop)
>     {
>         StringBuffer temp = new StringBuffer("");
> 
>         for (int i=0;i<loop;i++)
>         {
>           temp.append(makeString("this is ")).append("a
> ").append(makeString("concat test"));
>         }
> 
>         return temp.toString();
>     }

You can cut the garbage created by this sort of loop by increasing the
buffer allocation when the StringBuffer is initialised. StringBuffers
start with a very small buffer (16 bytes) so almost any action will
cause them to grow. In many cases you can estimate (with the aid of a
couple of quick tests) and allocate an appropriate amount.

When I started this thread it was to point out that blanket StringBuffer
usage did not always improve performance and in many common cases
decreased it. I'm not anti StringBuffer, I use them all the time I
wanted to increase the awareness of how Strings work. I think the
resulting conversations have certianly done that, that objective has
been obtained.

The other one (which kinda got forgotten) was to try and encourage
people to code in the simplest manor and leave the optimisations (for
the most part) until you're running your code through a profiler. That
way you'll be able to concetrate your efforts on the real hot stuff.
It's all well and good optimising the String access of a routine, but if
that routine is only taking 0.001% of your opperation time then you've
pretty much wasted your time :).

Oh and remember that hotspot will re-write your code on the fly,
inlining method calls and such, thus changing the performance
characteristics of the 

I think once the 1.0 archetecture stuff is in place and the code is
drives where we concentrate on finding the hot spots and quash them.
This will help make fop the best fo processor out there.

-k.

ps: Sorry if this is boring anyone :(.

-- 
Kevin O'Neill <[EMAIL PROTECTED]>
rocketred pty ltd


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, email: [EMAIL PROTECTED]

Reply via email to