Do you optimize?

D

Duane Morin

So I've got this J2EE application (which for the sake of disclosure is
all servlets and jsp, no ejb). And I find myself optimizing things at
the "get rid of concatted strings" level (i.e. no "foo"+"bar"). I
mention this to a friend who goes into a rant on how programmers
shouldn't do this anymore because it just doesnt matter, the compiler
does it all for you.

Thoughts? Do you still optimize when you're writing "enterprise apps"
(I'm ruling out the obvious cases of realtime systems, games, and
others where size/speed optimizations could be absoutely critical)?
At what point do you say screw it, I'm not getting enough bang for my
buck at this level, I'll let the compiler handle it?

Duane
 
T

Thomas Kellerer

Duane said:
So I've got this J2EE application (which for the sake of disclosure is
all servlets and jsp, no ejb). And I find myself optimizing things at
the "get rid of concatted strings" level (i.e. no "foo"+"bar"). I
mention this to a friend who goes into a rant on how programmers
shouldn't do this anymore because it just doesnt matter, the compiler
does it all for you.

Thoughts? Do you still optimize when you're writing "enterprise apps"
(I'm ruling out the obvious cases of realtime systems, games, and
others where size/speed optimizations could be absoutely critical)?
At what point do you say screw it, I'm not getting enough bang for my
buck at this level, I'll let the compiler handle it?

Duane
Yes I do, and there are a lot of places where the compiler cannot or will
not optimize stuff like that. And I honestly doubt that Sun's javac really
does that much optimization.

I do think String s = "foo" + "bar" would probably be optimized though :)

Especially on enterprise apps, it's extremely important to think about each
line, whether there is a better (faster) way to write it.

Just consider the following two lines:

someObject.getSomeNumber().substring(0,5);
someObject.getSomeNumber().substring(5,10);

Even when not using EJB's or related stuff, I wouldn't write it because I
try to minimize function calls as much as possible. But if someObject was a
remote object, you'd end up with two remote calls which might trigger a lot
more stuff in the background then you'd expect.

Thomas
 
A

Andy Fish

IMHO the important things are:

1. try to architect the app so it is fundamentally efficient and scalable -
this will have a far more effect than optimizing individual lines of code.
think about efficiency of network traffic, SQL statements, HTTP requests,
synchronization, as well as just java code.

2. if you optimize at the code level, only optimize those bits that are
likely to prove a problem. If you possibly afford it, wait until you know
where the problems are (or will be).

I agree with Thomas that compilers don't optimize as much as we might hope,
but I would recommend you try and do some benchmarks to figure out how much
faster a StringBuffer is than a concatenation. Unless that bit of code is
being executed 10,000 times a second on a CPU bound machine you may find
it's not worth the bother.

Bear in mind moore's law of hardware power. Maybe the machine you deploy on
will actually have twice the MHz you envisaged; Maybe adding another server
to the web farm or adding a hundred bucks worth of memory is cheaper than
fixing some inefficient code.

Just my two cents

Andy
 
M

Manish Jethani

Duane said:
So I've got this J2EE application (which for the sake of disclosure is
all servlets and jsp, no ejb). And I find myself optimizing things at
the "get rid of concatted strings" level (i.e. no "foo"+"bar"). I
mention this to a friend who goes into a rant on how programmers
shouldn't do this anymore because it just doesnt matter, the compiler
does it all for you.

Take this code for example:

String sql = "select id, name, age from employees"
+ "where name like '%" + name + "%'";

My colleague will optmise this code:

String sql = new StringBuffer(
"select id, name, age from employees")
.append("where name like '%")
.append(name)
.append("%'");

Honestly, which one is easier to read? To maintain? This is a
very simple query. In my application there were queries that
spanned 10-20 lines of SQL! So it gets really nasty at that point.

And when you're using EJB, you're already accepting several
performance penalties in favour of modularity, rapid application
development, code reuse, clustering, etc. Optimising string
concatenations is just so much of a waste of time, really.

My client deployed the app on huge Sun machines with loads of
RAM and CPU power. So my colleague's micro-optimisations didn't
serve any purpose except for irritating fellow developers.
Thoughts? Do you still optimize when you're writing "enterprise apps"
(I'm ruling out the obvious cases of realtime systems, games, and
others where size/speed optimizations could be absoutely critical)?
At what point do you say screw it, I'm not getting enough bang for my
buck at this level, I'll let the compiler handle it?

Please.

Manish
 
A

Andy Fish

and how long does it take to execute that line of SQL compared to building
it? - A factor of 10,000? a million? 100 million?
 
C

Chris Smith

Manish said:
Take this code for example:

String sql = "select id, name, age from employees"
+ "where name like '%" + name + "%'";

My colleague will optmise this code:

String sql = new StringBuffer(
"select id, name, age from employees")
.append("where name like '%")
.append(name)
.append("%'");

Honestly, which one is easier to read? To maintain?

As an interesting piece of trivia, your colleague's code is probably
just a tad slower than the original code.

--
www.designacourse.com
The Easiest Way to Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
P

pete kirkham

Manish said:
Duane Morin wrote:
Take this code for example:

String sql = "select id, name, age from employees"
+ "where name like '%" + name + "%'";

When the compiler expands the + macro to calls to StringBuffer and
combines adjacent literal strings, this becomes:

String sql = new StringBuffer().
.append("select id, name, age from employeeswhere name like '%")
.append(name)
.append("%'")
.toString();

which, when you look at the bytecode, is a couple of instructions less
than what the 'optimized' form compiles to.

However, I would optimize something like:
String makeString (boolean bar, int baz, SomeClass fido) {
String x = "foo" + (bar ? (Object)fido :
Integer.toString(baz));

if (baz>8) x += "wonder";

return x;
}
to
String makeString (boolean bar, int baz, SomeClass fido) {
StringBuffer x = new StringBuffer("foo");

if (bar) {
x.append(fido);
} else {
x.append(baz);
}

if (baz>8) x.append("wonder");

return x.toString();
}
because, as well as having fewer temporary strings and method calls,
that way to code can be seen to be constructing a string in stages
rather than nearly half the code being type conversions.


Pete
 
T

Thomas Kellerer

Andy said:
IMHO the important things are:

1. try to architect the app so it is fundamentally efficient and scalable -
this will have a far more effect than optimizing individual lines of code.
think about efficiency of network traffic, SQL statements, HTTP requests,
synchronization, as well as just java code.

You are absolutely right about the architecture. Some super tuned lines of
code will *never* fix a problem in the architecture. But once you have a
good architecture is worthwhile thinking about what you implement.
2. if you optimize at the code level, only optimize those bits that are
likely to prove a problem. If you possibly afford it, wait until you know
where the problems are (or will be).

I agree with Thomas that compilers don't optimize as much as we might hope,
but I would recommend you try and do some benchmarks to figure out how much
faster a StringBuffer is than a concatenation. Unless that bit of code is
being executed 10,000 times a second on a CPU bound machine you may find
it's not worth the bother.

While it's perfectly true that a line which only gets executed once during
application execution doesn't need that much attention (it does, when it
comes to startup times in a GUI application). But with a web based
application you can never be so sure how often a piece of code will be
executed, or how much data will be processed in one go.

You might anticipate that a given loop will loop over say 100 records/time,
but then once the application gets live and people start putting more and
more data into the system, you might come to the situation that the loop
has to handle 10000 records, and then it does matter how you write your code.

Bear in mind moore's law of hardware power. Maybe the machine you deploy on
will actually have twice the MHz you envisaged; Maybe adding another server
to the web farm or adding a hundred bucks worth of memory is cheaper than
fixing some inefficient code.

Ideally it should be that way, but sometimes even hardware manufactures
can't order new hardware :)

Regards
Thomas
 
T

Thomas Kellerer

Manish said:
Duane Morin wrote:




Take this code for example:

String sql = "select id, name, age from employees"
+ "where name like '%" + name + "%'";

My colleague will optmise this code:

String sql = new StringBuffer(
"select id, name, age from employees")
.append("where name like '%")
.append(name)
.append("%'");

Honestly, which one is easier to read? To maintain? This is a
very simple query. In my application there were queries that
spanned 10-20 lines of SQL! So it gets really nasty at that point.
I agree with you that the first version is much more maintainable, and
readable. In this case it does not make any difference. I think all the
Java tutorials even explain that the compiler will expand the first
statement to the second version. Maybe even only two appends (including
"where name like '%" already in the first constant.
And when you're using EJB, you're already accepting several
performance penalties in favour of modularity, rapid application
development, code reuse, clustering, etc. Optimising string
concatenations is just so much of a waste of time, really.

Nope. We did have situations where it mattered. Especially when you are
dealing with large data volumes!

And I think the opposite is true: *because* I do get a performance penalty
using EJB's I should take every precaution not to make the thing slower
(just think of my example with the remote call)


Regards
Thomas
 
M

Marco Schmidt

Duane Morin:
So I've got this J2EE application (which for the sake of disclosure is
all servlets and jsp, no ejb). And I find myself optimizing things at
the "get rid of concatted strings" level (i.e. no "foo"+"bar").

Adding literal Strings will lead to the complete String being stored
in the class file (in this case "foobar"). There is nothing to gain
here. In other cases, that may be different.
mention this to a friend who goes into a rant on how programmers
shouldn't do this anymore because it just doesnt matter, the compiler
does it all for you.

I'm tempted to agree with your friend, in general, but the compiler
doesn't do a lot of things. I recently heard about a Java compiler
(javac?) not converting

a / 8

to

a >> 3

which I find weird, because it is quite obvious. Maybe Hotspot does
this? Or is division just as fast as shifting these days?

Regards,
Marco
 
R

Roedy Green

"get rid of concatted strings" level (i.e. no "foo"+"bar").

The compiler does that for you. It is required by the language spec.

In the old days you primarily optimised for CPU speed. Today you
primarily optimise for clarity. Two reasons:

1. programmers are more expensive than CPUs.

2. programs are bigger and more complex, and unless you got for
clarity you will never get them debugged, and if you do, they won't
stay bug free as soon as a maintenance programmer gets his hands on
them.
 
R

Roedy Green

Thoughts? Do you still optimize when you're writing "enterprise apps"
(I'm ruling out the obvious cases of realtime systems, games, and
others where size/speed optimizations could be absoutely critical)?
At what point do you say screw it, I'm not getting enough bang for my
buck at this level, I'll let the compiler handle it?

Get a copy of JET and have a look at what it does in the way of
optimisation. What you do is feeble in comparison.

See http://mindprod.com/jgloss/jet.html

When you have a speed problem, nearly always you need a new algorithm,
unless someone has done some incredibly inept coding.
 
R

Roedy Green

and how long does it take to execute that line of SQL compared to building
it? - A factor of 10,000? a million? 100 million?

SQL still seem a strange way to do business. Use methods to compose
English-like ASCII sentences so that they can be parsed.


Surely it would make more sense to just make calls, passing binary
data that are handed direct to the lookup engine.

Heck, why not just pass complete Java objects back and forth, one per
row?
 
E

Eric Sosman

Marco said:
I'm tempted to agree with your friend, in general, but the compiler
doesn't do a lot of things. I recently heard about a Java compiler
(javac?) not converting

a / 8

to

a >> 3

which I find weird, because it is quite obvious. Maybe Hotspot does
this? Or is division just as fast as shifting these days?

If you find a Java compiler that performs this "optimization,"
file a bug report. (Hint: -5/8 == 0, but -5>>3 == -1.)
 
A

A Bag Of Memes

Duane Morin said:
So I've got this J2EE application (which for the sake of disclosure is
all servlets and jsp, no ejb). And I find myself optimizing things at
the "get rid of concatted strings" level (i.e. no "foo"+"bar"). I
mention this to a friend who goes into a rant on how programmers
shouldn't do this anymore because it just doesnt matter, the compiler
does it all for you.

Thoughts? Do you still optimize when you're writing "enterprise apps"
(I'm ruling out the obvious cases of realtime systems, games, and
others where size/speed optimizations could be absoutely critical)?
At what point do you say screw it, I'm not getting enough bang for my
buck at this level, I'll let the compiler handle it?

1. Write code that is easy to understand.
2. Analyze performance.
3. Optimize bottlenecks if needed.

The most expensive part of large software projects is maintenance, so
keeping code easy to understand is the primary consideration. Optimization
tends to reduce readability. Optimizing code that rarely executes wastes
expensive developer time.
 
A

A Bag Of Memes

Marco Schmidt said:
Duane Morin:


Adding literal Strings will lead to the complete String being stored
in the class file (in this case "foobar"). There is nothing to gain
here. In other cases, that may be different.


I'm tempted to agree with your friend, in general, but the compiler
doesn't do a lot of things. I recently heard about a Java compiler
(javac?) not converting

a / 8

to

a >> 3

which I find weird, because it is quite obvious. Maybe Hotspot does
this? Or is division just as fast as shifting these days?

Java compilers are not supposed to optimize. That's left for the VM. The
compiler has to provide a simple bytecode representation of the code that
can be quickly optimized at run time. Java's bytecode structure was
designed with this in mind.
 
R

Roedy Green

As an interesting piece of trivia, your colleague's code is probably
just a tad slower than the original code.

You need a good estimate for size of the final string to ace out
simple +. Otherwise the StringBuffer has to take time out to grow
itself.
 
R

Roedy Green

1. Write code that is easy to understand.
2. Analyze performance.
3. Optimize bottlenecks if needed.

I will tell a story to illustrate my two points. I was working on a
project for the Apple Mac, the very first app ever written for the
thing. We developed on Lisas using the strangest documentation you
ever saw, sort of a wish list of features.

The floating point at the time was handled by the Mac SANE library
which was a software emulation.

I determined the bottleneck was in the divisions done to scale the
data for graphing.

I persuaded my boss to let my friend Hugh McDonald have go at it. He
is the ultimate bit fiddler. He wrote a scaling routine in 68000
assembler using pure ints. It FLEW. All he wanted was the challenge
and a bottle of good wine for thanks.


My points: if the crucial section is small, give it to an expert to
fix. If you really want it to fly, don't be afraid of assembler.
Keep the original Java or C around for ports to other platforms.
 
J

Jon A. Cruz

Thomas said:
While it's perfectly true that a line which only gets executed once
during application execution doesn't need that much attention (it does,
when it comes to startup times in a GUI application). But with a web
based application you can never be so sure how often a piece of code
will be executed, or how much data will be processed in one go.

You might anticipate that a given loop will loop over say 100
records/time, but then once the application gets live and people start
putting more and more data into the system, you might come to the
situation that the loop has to handle 10000 records, and then it does
matter how you write your code.


But this is exactly the kind of situation where optimizing algorithms
pays of far more than optimizing code.


However... there is a much larger issue that you are missing.

Java optimizations mean nothing!!!!

:)

That's why IBM's Jikes doesn't even do it.

Remember, there are *two* compilers involved. One is the
Java-to-bytecode compiler. The other is the bytecode-to-native compiler.
The latter lives in the JVM.

So in theory what will happen on a Hotspot style VM is that once you hit
the load cases where your 100 records at a time Java gets hit with 10000
records at a time, it will detect the change in the hot spot and
recompile it using actual run-time performance metrics to choose which
methods to use in the native code optimizations.

Then again, in practice it's the database access that will kill you, not
the java execution speed.
 
H

Hendrik Maeder

When the compiler expands the + macro to calls to StringBuffer and
combines adjacent literal strings, this becomes:

How do you explain these results:
Testing string concat...

Testing stringbuffer...

Results:

concat time: 2333ms total

buffer time: 20ms total

Does not look like ist becomes the same bytecode, though it should be identical. Using JDK 1.4.2 by the way...

This is the test class:
-- BEGIN CODE --
public class Test {

public static final int CYCLES = 10000;

public static void main(String argv[]) {

String s1 = new String("test");

String s2 = new String(" me");

String s3 = s1;

StringBuffer s4 = new StringBuffer(s1);

long time, time1, time2;

System.out.println("Testing string concat...");

time = System.currentTimeMillis();

for (int i=0; i<CYCLES; i++) {

s3 = s3 + s2;

}

time1 = System.currentTimeMillis() - time;

System.out.println("Testing stringbuffer...");


time = System.currentTimeMillis();

for (int i=0; i<CYCLES; i++) {

s4 = s4.append(s2);

}

time2 = System.currentTimeMillis() - time;


System.out.println("Results:");

System.out.println("concat time: " + time1 + "ms total");

System.out.println("buffer time: " + time2 + "ms total");

}

}

-- END CODE --
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,015
Latest member
AmbrosePal

Latest Threads

Top