вторник, 24 июня 2008 г.

When Java can be faster than C++

In practice, Java always slower than C/C++. But, i found one occurrence when Java really more fast. Let's see.

At first, i write little C++ code, test.cc like this:

#define ALLOCATIONS 200000000

int main(void) {
int i;

for( i = 0; i < ALLOCATIONS; ++i )
delete (new int(i));

}

then, compile and run:

cy6ergn0m@d-espb04-127-128 ~/test $ g++ -O3 test.cc
cy6ergn0m@d-espb04-127-128 ~/test $ time ./a.out
./a.out 22,86s user 0,01s system 100% cpu 22,867 total
cy6ergn0m@d-espb04-127-128 ~/test $

Note time: 22.86s

Then, i wrote in Java like this:

public class Main3 {

private static final int SZ = 200000000;

public static void main ( String[] args ) {

for( int i = 0; i < SZ; ++i )
new Integer(i);
System.gc();
}
}

At last, i use System.gc() to call GC because, someone can say, that this code does not deletes anything..

Ok, lets run it:

cy6ergn0m@d-espb04-127-128 ~/NetBeansProjects/JavaApplication12 $ time java -jar dist/JavaApplication12.jar
java -jar dist/JavaApplication12.jar 2,34s user 0,13s system 99% cpu 2,489 total

Note time here: 2.34s


Summary
This test shows us, that Java has more fast allocator/deallocator. C++ take too many time for object allocation. Here you can see that it's about 10 times slower (22.86s vs 2.34s).

But, if I'll try to do with allocated objects something - C++ will faster.

Currently, it only first incident when Java faster than C that I saw. If somebody know any other, please, send me link.

четверг, 1 мая 2008 г.

Big Endian and Little Endian

Here my util class to manipulate with endians and java int/long





1 /***************************************************************************
2 * Copyright (C) 2007 by cy6ergn0m *
3 * *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20 /*
21 * Endians.java
22 *
23 * Created on 21 june 2007, 0:03
24 *
25 */
26
27 package libim.utils.binary;
28
29 /**
30 *
31 * @author cy6erGn0m
32 */
33 public abstract class Endians {
34
35 public static final byte[] int16_to_big_endian ( int number ) {
36 byte[] result = new byte[ 2 ];
37 result[1] = (byte) ( number % 256 );
38 result[0] = (byte) ( ( number & 0xff00 ) >> 8 );
39 return result;
40 }
41
42 public static final byte[] int16_to_little_endian ( int number ) {
43 byte[] result = new byte[ 2 ];
44 result[0] = (byte) ( number % 256 );
45 result[1] = (byte) ( ( number & 0xff00 ) >> 8 );
46 return result;
47 }
48
49 public static final byte[] int32_to_big_endian ( int number ) {
50 byte[] result = new byte[ 4 ];
51 result[3] = (byte) ( number % 256 );
52 result[2] = (byte) ( ( number & 0xff00 ) >> 8 );
53 result[1] = (byte) ( ( number & 0xff0000 ) >> 16 );
54 result[0] = (byte) ( ( number & 0xff000000 ) >> 24 );
55 return result;
56 }
57
58 public static final byte[] int32_to_little_endian ( int number ) {
59 byte[] result = new byte[ 4 ];
60 result[0] = (byte) ( number % 256 );
61 result[1] = (byte) ( ( number & 0xff00 ) >> 8 );
62 result[2] = (byte) ( ( number & 0xff0000 ) >> 16 );
63 result[3] = (byte) ( ( number & 0xff000000 ) >> 24 );
64 return result;
65 }
66
67 public static final byte[] int64_to_big_endian ( long number ) {
68 byte[] result = new byte[ 8 ];
69 for ( int i = 7 ; i >= 0 ; i-- ) {
70 result[i] = (byte) ( number & 0xff );
71 number >>= 8;
72 }
73 return result;
74 }
75
76 public static final byte[] int64_to_little_endian ( long number ) {
77 byte[] result = new byte[ 8 ];
78 for ( int i = 0 ; i < 8 ; i++ ) {
79 result[i] = (byte) ( number & 0xff );
80 number >>= 8;
81 }
82 return result;
83 }
84
85 public static final int byte2int ( byte b ) {
86 return ( b < 0 ) ? ( 256 + b ) : b;
87 }
88
89 public static final int byte2int ( int b ) {
90 return ( b < 0 ) ? ( 256 + b ) : b;
91 }
92
93 public static final int big_endian_to_int16 ( byte[] bytes ) {
94 if ( bytes.length == 0 ) {
95 return 0;
96 } else if ( bytes.length == 1 ) {
97 return byte2int( bytes[0] );
98 } else {
99 return ( byte2int( bytes[0] ) << 8 ) | byte2int( bytes[1] );
100 }
101 }
102
103 public static final int little_endian_to_int16 ( byte[] bytes ) {
104 if ( bytes.length == 0 ) {
105 return 0;
106 } else if ( bytes.length == 1 ) {
107 return byte2int( bytes[0] );
108 } else {
109 return ( byte2int( bytes[1] ) << 8 ) + byte2int( bytes[0] );
110 }
111 }
112
113 public static final int big_endian_to_int32 ( byte[] bytes ) {
114 if ( bytes.length < 4 ) {
115 int result = 0;
116 for ( byte b : bytes ) {
117 result = ( result << 8 ) | b;
118 }
119 return result;
120 } else {
121 return ( byte2int( bytes[0] ) << 24 ) | ( byte2int( bytes[1] ) << 16 ) | ( byte2int( bytes[2] ) << 8 ) | ( byte2int( bytes[3] ) );
122 }
123 }
124
125 public static final int little_endian_to_int32 ( byte[] bytes ) {
126 if ( bytes.length < 4 ) {
127 int result = 0;
128 for ( byte b : bytes ) {
129 result = ( result >> 8 ) | ( b << 24 );
130 }
131 return result;
132 } else {
133 return ( byte2int( bytes[3] ) << 24 ) | ( byte2int( bytes[2] ) << 16 ) | ( byte2int( bytes[1] ) << 8 ) | ( byte2int( bytes[0] ) );
134 }
135 }
136
137 public static final long big_endian_to_int64 ( byte[] bytes ) {
138 long result = 0;
139 for ( byte b : bytes ) {
140 result = ( result << 8 ) | b;
141 }
142 return result;
143 }
144
145 public static final long little_endian_to_int64 ( byte[] bytes ) {
146 long result = 0;
147 for ( byte b : bytes ) {
148 result = ( result >> 8 ) | ( b << 24 );
149 }
150 return result;
151 }
152 }
153
154

SQLInvocable

Here my SQLInvocable pattern. I dislike JPA's such as hibernate/toplink, and I use pure JDBC.


Base class for SQL action is:



1 /*
2 *
3 * Currently unlicensed
4 */
5
6 package cy6ergn0m.myweb.db.procs;
7
8 import cy6ergn0m.myweb.cfg.AppConfig;
9 import cy6ergn0m.myweb.exceptions.DatabaseException;
10 import java.sql.Connection;
11 import java.sql.ResultSet;
12 import java.sql.SQLException;
13 import java.sql.Statement;
14
15 /**
16 *
17 * @author cy6erGn0m <cy6erGn0m@gmail.com>
18 */
19 public abstract class SQLInvocable {
20
21 /**
22 * Call this method to execute SQL
23 * @throws cy6ergn0m.myweb.exceptions.DatabaseException
24 */
25 public final void invoke() throws DatabaseException {
26 Connection connection = null;
27 try {
28 connection = AppConfig.getConfig().getConnection();
29 execute( connection );
30 } catch( SQLException e ) {
31 throw new DatabaseException( e );
32 } finally {
33 try {
34 if( connection != null )
35 connection.close();
36 } catch( SQLException e ) {
37 e.printStackTrace();
38 }
39 }
40 }
41
42 protected abstract void execute( Connection connection ) throws SQLException, DatabaseException;
43
44 protected static final void closeResultSet( ResultSet rs ) {
45 try {
46 if( rs != null )
47 rs.close();
48 } catch ( SQLException e ) {
49 e.printStackTrace();
50 }
51 }
52
53 protected static final void closeStatement( Statement st ) {
54 try {
55 if( st != null )
56 st.close();
57 } catch ( SQLException e ) {
58 e.printStackTrace();
59 }
60 }
61 }
62
63


Then, implement method execute, like this:




1 /*
2 *
3 * Currently unlicensed
4 */
5
6 package cy6ergn0m.myweb.db.procs;
7
8 import cy6ergn0m.myweb.exceptions.DatabaseException;
9 import java.sql.Connection;
10 import java.sql.PreparedStatement;
11 import java.sql.ResultSet;
12 import java.sql.SQLException;
13
14 /**
15 *
16 * @author cy6erGn0m <cy6erGn0m@gmail.com>
17 */
18 public class GetMessagesCountSQL extends SQLInvocable {
19
20 private static final String getMessageCountSql = "select count(id) from messages where user_reciever = ? and was_read = 0";
21
22 private int userId;
23 private int count;
24
25 public void setUserId ( int userId ) {
26 this.userId = userId;
27 }
28
29 public int getCount () {
30 return count;
31 }
32
33 @Override
34 protected void execute ( Connection connection ) throws SQLException,
35 DatabaseException {
36 PreparedStatement st = null;
37 ResultSet rs = null;
38 try {
39 st = connection.prepareStatement( getMessageCountSql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY );
40 st.setInt( 1, userId );
41 rs = st.executeQuery();
42 if( rs.next() )
43 count = rs.getInt( 1 );
44 } finally {
45 closeResultSet( rs );
46 closeStatement( st );
47 }
48 }
49
50 }
51
52


And now, just use:



GetMessagesCountSQL sql = new GetMessagesCountSQL();
sql.setUserId( userId );
sql.invoke();
count = sql.getCount();

fast int to string

More fast int to string (in decimal base) implementation for Java. It uses external bytes buffer an it can be useful if need write number to stream as fast as possible.





1 package cy6ergn0m;
2
3 /**
4 *
5 * @author cy6erGn0m cy6erGn0m at gmail dot com
6 */
7 public class NumbersChars {
8
9 final static int[] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
10 99999999, 999999999, Integer.MAX_VALUE
11 };
12
13 final static byte[] digits = {
14 '0', '1', '2', '3', '4', '5',
15 '6', '7', '8', '9', 'a', 'b',
16 'c', 'd', 'e', 'f', 'g', 'h',
17 'i', 'j', 'k', 'l', 'm', 'n',
18 'o', 'p', 'q', 'r', 's', 't',
19 'u', 'v', 'w', 'x', 'y', 'z'
20 };
21 final static byte[] DigitTens = {
22 '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
23 '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
24 '2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
25 '3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
26 '4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
27 '5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
28 '6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
29 '7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
30 '8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
31 '9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
32 };
33 final static byte[] DigitOnes = {
34 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
35 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
36 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
37 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
38 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
39 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
40 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
41 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
42 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
43 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
44 };
45
46 // Requires positive x
47 static int stringSize ( int x ) {
48 for ( int i = 0;; i++ )
49 if ( x <= sizeTable[i] )
50 return i + 1;
51 }
52
53 static void getChars ( int i, int index, byte[] buf ) {
54 int q, r;
55 int charPos = index;
56 byte sign = 0;
57
58 if ( i < 0 ) {
59 sign = '-';
60 i = -i;
61 }
62
63 // Generate two digits per iteration
64 while ( i >= 65536 ) {
65 q = i / 100;
66 // really: r = i - (q * 100);
67 r = i - ( ( q << 6 ) + ( q << 5 ) + ( q << 2 ) );
68 i = q;
69 buf[--charPos] = DigitOnes[r];
70 buf[--charPos] = DigitTens[r];
71 }
72
73 // Fall thru to fast mode for smaller numbers
74 // assert(i <= 65536, i);
75 for (;;) {
76 q = ( i * 52429 ) >>> ( 16 + 3 );
77 r = i - ( ( q << 3 ) + ( q << 1 ) ); // r = i-(q*10) ...
78
79 buf[--charPos] = digits[r];
80 i = q;
81 if ( i == 0 )
82 break;
83 }
84 if ( sign != 0 )
85 buf[--charPos] = sign;
86 }
87
88 public static int i2s ( int i, byte[] buffer ) {
89 int size = ( i < 0 ) ? stringSize( -i ) + 1 : stringSize( i );
90 if ( size > buffer.length )
91 throw new IllegalArgumentException( "buffer too small" );
92 getChars( i, size, buffer );
93 return size;
94 }
95
96 }
97
98

Ушёл от нас человек, принесший, кроме многих важных открытий, немалую беде: LSD.
http://news.bbc.co.uk/hi/russian/sci/tech/newsid_7374000/7374866.stm
102 года прожил! Удивительно! Не часто люди так долго живут.. а ведь он пробовал LSD на себе.. :)

понедельник, 21 апреля 2008 г.

WriteLock

Сегодня наколбасил небольшую блокировочку на Java. Предназначена для случаев, когда процент изменений мал по сравнению с процентом доступа к данным. В таком случае применение этой блокировки целесообразно. Блокировка позволяет работать многим потокам для чтения, но не позволяет работать многим потокам для записи. Кроме того, исключает работу читателей во время работы писателя. Иными словами в критическом участке работают либо много читателей, либо только один писатель.

Вот этот тест предназначен для тестирования этой блокировки:



package javaapplication13;

/**
*
* @author cy6ergn0m
*/
public class Main {

static class ReaderThread extends Thread {

@Override
public void run () {
try {
for( int i = 0; i < 1000; ++i ) {
wl.beginRead();
int now = safeObject;
sleep( 50 );
if( now != safeObject ) {
System.err.println( "safe object damaged!" );
System.err.flush();
System.exit( -1 );
}
wl.endRead();
}
} catch ( InterruptedException ex ) {
ex.printStackTrace();
}
}

}

static class WriterThread extends Thread {

@Override
public void run () {
try {
for( int i = 0; i < 1000; ++i ) {
wl.beginWrite();
safeObject++;
wl.endWrite();
}
} catch ( InterruptedException ex ) {
ex.printStackTrace();
}
}

}

static final WriteLock wl = new WriteLock(false);
static int safeObject = 0;
public static void main(String[] args) throws InterruptedException {
Thread ths[] = new Thread[ 3000 ];
for( int i = 0; i < ths.length; ++i ) {
if( (i & 1) == 0 )
ths[i] = new ReaderThread();
else
ths[i] = new WriterThread();
ths[i].setPriority( Thread.MIN_PRIORITY );
}

for( Thread th : ths )
th.start();

for( Thread th : ths )
th.join();
}

}




А вот собственно сам код блокировки


package cy6ergn0m;

/**
* WriteLock is a two way lock. Expected to be used by two types of threads.
* First type: readers. Readers threads can work at the same time.
* Second type: writers. Writers can't work simultaneously.
* At any time in critical section can work many readers
* or only one writer.
* WriteLock has one parameter: aggressiveExclusion. This is a flag.
* If aggressiveExclusion is true, all readres waits while all writers will
* be done, if false, writer will wait until readers attempts to enter section.
* It looks like priority. If true, writers has greather priority, if false,
* readres has greather priority.
*
* @author cy6erGn0m <cy6erGn0m@gmail.com>
*/
public class WriteLock {
private final boolean aggressiveExclusion;
private Object lock = new Object();
private boolean writeNow = false;
private int writePendings = 0;
private int readers = 0;

/**
* sets aggressiveExclusion = true
*/
public WriteLock () {
aggressiveExclusion = true;
}

public WriteLock ( boolean aggressiveExclusion ) {
this.aggressiveExclusion = aggressiveExclusion;
}

public void beginWrite() throws InterruptedException {
synchronized( lock ) {
writePendings++;
while( writeNow || readers > 0 )
lock.wait();
writeNow = true;
writePendings--;
}
}

public void endWrite() {
synchronized( lock ) {
if( !writeNow )
throw new IllegalStateException( "notin write section" );
writeNow = false;
lock.notifyAll();
}
}

public void beginRead() throws InterruptedException {
synchronized( lock ) {
while( writeNow || (aggressiveExclusion && writePendings > 0 ) )
lock.wait();
readers++;
}
}

public void endRead() {
synchronized( lock ) {
readers--;
lock.notifyAll();
}
}
}

Сегодня нарыл много записей хорового пения. Не всё в хорошем качестве, но много реально качественного исполнения.

http://vkontakte.ru/audio.php?33925