Thursday, January 20, 2011

Why thread priority rarely matters

Overview

Its is tempting to use the Thread.setPriority() option in Java. However for many applications this is more a comment for the developer than something which will make a measurable difference. esp. with multi-core systems.

Why it usually doesn't matter

If you have plenty of free CPU, every thread which can run will run. The OS has no reason not to run a low priority thread or process when it has free resources. If your system is close to 100% of CPU on every core, the OS has to make a choice as to how much time each thread or process gets on the CPU and it is likely to give favour to higher priority threads over lower priority threads, (many OSes ignore the hint) and other factors are likely to matter as well.
This priority only extends to raw CPU. Threads compete equally for CPU cache, heap space, CPU to memory bandwidth, file cache, disk IO, network IO and everything else. If any of these resource are in competition, they are all equal.
To set a high priority on Windows you need to be an administrator and on Linux you need to be root to set the priority of a thread. Different Implementations and OSes can ignore this hint.

Summary

If your application is heavily CPU bound, using every core, not using any other system resources significantly like IO or memory and your OS doesn't ignore the hint, the thread priority might make a difference. If in doubt, I wouldn't bother setting it because someone might think it does something. ;)

Wednesday, January 12, 2011

Tuning buffer sizes


Overview


When the typical read/write size is small, using a buffer can make a significant improvement in performance. However when reading/writing large amounts of data, additional buffered doesn't help and can add a small amount of overhead.

Additionally, it can be tempting to assume; the larger the buffer the better. However is appears a more modest buffer size, around the size of your L1 cache could be better. e.g 8 KB to 32 KB.


The test


In the following test I compared using buffered and unbuffered reads and writes to a temporary file on a tmpfs filesystem (ram disk)

Size of
read/write
Unbuffered
Writes
  Buffered
Writes
Unbuffered
Reads
  Buffered
Reads
12 MB/s86 MB/s3 MB/s72 MB/s
24 MB/s165 MB/s6 MB/s147 MB/s
48 MB/s333 MB/s11 MB/s291 MB/s
817 MB/s578 MB/s24 MB/s560 MB/s
1634 MB/s920 MB/s49 MB/s983 MB/s
3267 MB/s1,345 MB/s99 MB/s1,679 MB/s
64133 MB/s1,746 MB/s198 MB/s2,518 MB/s
128254 MB/s2,024 MB/s391 MB/s3,387 MB/s
256463 MB/s2,172 MB/s742 MB/s4,104 MB/s
512798 MB/s2,270 MB/s1,334 MB/s4,549 MB/s
1,0241,270 MB/s2,299 MB/s2,355 MB/s4,752 MB/s
2,0481,789 MB/s2,310 MB/s3,704 MB/s4,923 MB/s
4,0962,287 MB/s2,301 MB/s5,324 MB/s4,859 MB/s
8,1922,589 MB/s2,497 MB/s6,346 MB/s6,142 MB/s
16,3842,534 MB/s2,559 MB/s5,764 MB/s5,697 MB/s
32,7682,591 MB/s2,561 MB/s5,793 MB/s5,723 MB/s
65,5362,613 MB/s2,581 MB/s5,861 MB/s5,883 MB/s
131,0722,580 MB/s2,581 MB/s5,401 MB/s5,405 MB/s
262,1441,918 MB/s1,907 MB/s3,269 MB/s3,262 MB/s
524,2881,749 MB/s1,734 MB/s2,845 MB/s2,851 MB/s
1,048,5761,471 MB/s1,469 MB/s2,501 MB/s2,502 MB/s


The default size of a BufferedInputStream and BufferedOutputStream is 8KB. This is part of the reason why they don't help at this point and larger.


The code


BufferTest.java