S
Steve Wampler
Olivier said:Ok, but how can I do the same thing in Java ?
By the way, I do not want to attack java (that I use daily). I just want
to understand ...
Try the following version (lifted almost verbatim from an earlier thread).
Note that it includes instrumentation code that could be stripped out
in 'Real Life'. Also note that the methods it uses could be generalized
and provided as part of a 'performance' package. (I didn't write the
methods, incidently.)
---------------------------------------------------------------------
class T1 {
static public void main(String[] argv) {
int lim = new Integer(argv[0]);
int nbench = new Integer(argv[1]);
int b;
for (b=0; b < nbench; b++) {
System.err.println("Bench " + b);
Date start = new Date();
try {
write3fastItoS2(lim);
}
catch ( Exception e) {
System.err.println("Exception occurred");
System.err.println(e.toString());
}
Date now = new Date();
System.err.println("Took " + ((now.getTime() -
start.getTime())/1000.0) + " seconds");
}
}
static public void write3fastItoS2( int lim ) throws IOException {
BufferedOutputStream os = new BufferedOutputStream( System.out );
String message2 = "abcdefghijk ";
byte[] mbuff = message2.getBytes();
int mlength = mbuff.length;
AsciiByteBuff ibuff = new AsciiByteBuff();
ibuff.ascii = new byte [Integer.toString(Integer.MAX_VALUE).length()
+ 2 ];
for( int i = 0; i < lim; i++ ) {
os.write( mbuff, 0, mlength );
fastItoS2( ibuff, i );
os.write(ibuff.ascii, ibuff.start, ibuff.slength );
os.write('\n');
}
os.close();
}
/** Converts a POSITIVE integer to a byte [], with an emphasis on speed.
*
* @param buff The start, length and ASCII values are stored in this buffer.
* The buffer must be therefore at least the size of Integer.MAX_VALUE + 2.
* buff.start stores the offset of the first ASCII character.
* buff.length stores the length of the ASCII character string.
* Strings are written to the end of the buffer.ascii array.
* @param i MUST BE POSITIVE. This is not tested by the method. Stuff
* will explode in spectacular ways if you pass this routine a negative
* integer.
*/
static void fastItoS2( AsciiByteBuff buff, int i ) {
int index = buff.ascii.length - 1;
int q = i;
int r;
for(; {
r = q % 10;
q = q / 10;
buff.ascii[index--] = digits[r];
if( q == 0 ) break;
}
buff.start = (index + 1);
buff.slength = (buff.ascii.length - 1 - index);
}
private static class AsciiByteBuff {
public int start;
public int slength;
public byte [] ascii;
}
private static byte [] digits = { '0', '1', '2', '3', '4',
'5', '6', '7', '8', '9' };
}
----------------------------------------------------------------
Yes, it's quite a bit longer than the C version, but by rewriting
most of it into a 'performance package' (presumably with additional
methods for other, similar operations), the remaining code could
be written in not much more lines than the C one. (The fact that
no one [as far as I know] has written such a performance package
probably means that there hasn't been a perceived need for it!)
Performance with a single run (to match the C version) through the
key code (SUN's JDK 1.6):
---------------------------------------------------------------
->time java -server T1 1000000 1 | cat >/dev/null
Bench 0
Took 0.251 seconds
java -server T1 1000000 1 0.31s user 0.03s system 88% cpu 0.384 total
cat > /dev/null 0.00s user 0.02s system 5% cpu 0.333 total
---------------------------------------------------------------
while on the same machine, using gcc 4.1.1 (-O4) the original C version gives:
---------------------------------------------------------------
->time ./t1 | cat >/dev/null
../t1 0.29s user 0.02s system 97% cpu 0.319 total
cat > /dev/null 0.00s user 0.02s system 6% cpu 0.318 total
->
---------------------------------------------------------------
And to show what Hot Spot can do, let's give it a chance to really kick
in (it doesn't take long):
---------------------------------------------------------------
->time java -server T1 1000000 20 | cat >/dev/null
Bench 0
Took 0.239 seconds
Bench 1
Took 0.195 seconds
Bench 2
Took 0.194 seconds
Bench 3
Took 0.199 seconds
Bench 4
Took 0.198 seconds
Bench 5
Took 0.207 seconds
Bench 6
Took 0.194 seconds
Bench 7
Took 0.192 seconds
Bench 8
Took 0.194 seconds
Bench 9
Took 0.194 seconds
Bench 10
Took 0.196 seconds
Bench 11
Took 0.192 seconds
Bench 12
Took 0.193 seconds
Bench 13
Took 0.194 seconds
Bench 14
Took 0.194 seconds
Bench 15
Took 0.198 seconds
Bench 16
Took 0.201 seconds
Bench 17
Took 0.193 seconds
Bench 18
Took 0.194 seconds
Bench 19
Took 0.195 seconds
java -server T1 1000000 20 4.01s user 0.04s system 99% cpu 4.083 total
cat > /dev/null 0.00s user 0.01s system 3% cpu 0.319 total
->
---------------------------------------------------------------
Whereas 20 runs of the C version would produce no significant difference
from the original. (Feel free to instrument the C version in the same way.)
Does this prove Java is faster than C? Of course not. I imagine one could
do similar hand optimizations on the C side to get a quicker version there
as well (or find a better C compiler!). In fact, I'm *sure* one could also
write a similar 'performance package' for C...
But it does help show that Java isn't inherently as slow as some would claim.
(If someone who's not as cheap as I am has access to JET, I'd *love* to see
what JET does with this code [and the original Java version].)