|
|
|
Back to newsletter 031 contents
Have you ever been to Kroger's? Given the diverse distribution of this newsletter, my guess is that most of you have not even heard of Kroger's. I had never been to Kroger's until late one night I needed a few groceries. Kroger's is large grocery store chain that is open 24 hours a day. What is interesting about this change is that they have an automated checkout system, which allows you to calculate the bill and pay for it with little if any human intervention. Here is how it works.
The automated checkout system is limited to express checkout rules. In other words, one can checkout 15 or fewer items. The automated checkouts are traditionally situated in the front of the store. Each point-of-sale contains four kiosks, which are monitored by a single employee. Customers walk up to the kiosk and start the checkout process by scanning those items that have bar codes. Once an item is scanned, you are required to set it in a bag that is sitting on end of the kiosk. Once an item is placed in the bag, it cannot be removed without causing the process to be halted and employee intervention to continue. Items, such as vegetables, that do not have bar codes are identified and priced by the employee. A camera system is installed at each kiosk so that the employee can perform this task from a centralized location. Once all of the items have been accounted for, you then proceed to pay either using cash or a bankcard.
The do-it-yourself checkout experience is much slower than having a store clerk do the work. But, with four stations, you do spend less time queuing, which makes up for the slower checkout time. So, you don't get 4-times throughput on the system but it is better than 1-time. And given that checkout is both a psychological and labor cost center, improving overall service time can make a difference in the efficiency of the overall system. Now lets look at some Java Performance tips.
Our journey begins at the Java Ranch where we find the ranch hands have taken over the conversation for a change. The first question asked about the downsides to calling System.gc(). The only downside reported is that the call may not do anything. The specification only guarantees that GC will be run before the VM throws an OutOfMemoryError. From a more pragmatic point of view, I've never seen Sun's VM ignore a request to perform a GC. And as the bartender pointed out, if you know that your application is going to pause and you know that the heap contains a lot of dead objects, then it makes sense to make a call to System.gc().
I'd go further, if you know you have a natural pause in the application, why not make the call. Doing this may simulate incremental GC which may, or may not actually save you pause time in the near future. On the other hand, where there are no natural pauses, I know that calling System.gc() can slow down the system by forcing the garbage collector to run when it would not need to. This is sufficiently performance draining that the latest JVMs have a flag which, when set, tells the JVM to completely ignore calls to System.gc().
Once the dust had settled on the question of garbage collection, a greenhorn walked in and started up on stateless session beans. He had a whole wagon full of questions about session pooling, how many clients can a session bean service, and what happens if the application crashes when it has 1000s of clients executing methods. The bartender quickly quieted the green horn down with a shot of wisdom. First, the J2EE specification does not require an application server to implement session bean pooling. In fact, I've heard rumors that some vendors have not even bothered to do anything else except setup a 1 to 1 client to stateless session bean ratio.
But, having said this, better not store intra-call state in the bean as the spec deliberately prohibits this activity. If pooling is in place then you can expect that the average number of beans that you'll need is the average service time multiplied by the frequency with which calls are made. And of course, these values could change for each every service offered by every stateless session bean. Problem is, this only defines an average. Actual values may vary greatly leaving some clients out in the cold for a very long time unless the pool is allowed to grow in size. All in all, it's not a subject for greenhorns to get lassoed into.
Just to prove that it is not only the greenhorns that have troubles, a ranch hand walked into the saloon after encountering an OutOfMemoryError. He was trying to parse two 45-megabyte XML files. Now it's not clear if he was using a SAX or DOM parser, but it was suggested by the bartender that a 45-Megabyte XML file could produce upwards of 400 Megabytes of garbage. Now, that is a lot of shoveling for anyone to take on let alone a poor VM with not enough memory to handle the task. Anyway, the issue is that the default VM settings will not tolerate this type of memory consumption. They can be set using -Xmx option. In this instance, it may make sense to go one step further and set the -Xms option to the same value so that the heap is fixed in size and time is not wasted resizing it. So, with this problem solved, lets trip over to the server side to see what the city slickers are up to.
The first question up for discussion is; is the JDO faster than the JDBC? On the surface, it sounds like we have two potentially competing technologies but, that myth is dispelled as a post quite correctly points out that the JDO is a higher level of abstraction that depends upon the JDBC. Since the JDO is layered on top, it cannot be faster. So, why would one use a technology that cannot be faster? In this case the answer is that it is much faster to develop object relational mappings using the JDO. As long as performance is adequate, good design wins over good performance.
Have you been missing submissions from ECPerf? Well, rest assured, you are not alone. It's not that ECPerf is no longer being used. In fact, I know of at least one organization that is relying on it. So, where has it gone? Well, it is now a Spec project. But, don't expect the frenzy of announcements that we once saw. An ECPerf benchmarking exercise is expensive to conduct. Consequently, only the big boys can afford them. The new name is SPECjAppServer200x.
Finally, we have a question regarding object relational mappings. The poster is looking for a load-on-demand feature. The response was overwhelming to use TopLink. I've worked with TopLink so, I have a little bias for the tool. In addition, if you recall our interview with Mike Norman, then you know that Oracle is positioning this product for performance. When asked about performance, the answer in the past has been, "how fast is your bicycle?" As cute as the answer is, TopLink and other O/R mapping tools do cost but, considering that 30-40% of an application team's time maybe working on solving that problem, the price tag of 7000USD/CPU can be recouped fairly quickly. If you use the Oracle 9i application server stack, then it's included which makes the ROI even shorter.
For the last time, we move on to review the happenings in at www.javagaming.com. The site has been moved to www.java.net and it would seem that the discussion groups have been discontinued whilst the administrators move house. With that, we start with a post regarding synchronization. The question is, is this a bad idea:
SomeObject someObject ; // synchronized( someObject) { doSomeStuff(); if ( someCondition) someObject = new SomeObject(); doSomeOtherStuff(); }
In short, the answer is, this is no way to protect a critical block. For starters,
synchronization relies on a thread acquiring a monitor in an object, not the reference
to the object. So, when someCondition
is met and the object reference
someObject
is altered, that leaves the block vulnerable to another thread
to enter at the same time. Fortunately, assignment is an atomic operation and as such,
will not leave the VM in the situation where someObject is null and hence cause an
internal failure in the VM.
If there is one thing in particular that game programmers want, it's an accurate timer. The gaming experience depends upon it. Without it, the game will not flip through frames at a constant rate of speed. This will give the users a jittery experience. So, it was not surprising when the topic of timers came up again.
The question is, will System.currentTimeMillis() start falling behind if the computer is under heavy load? It turns out, there are two gotchas. The first is that different systems have different clock resolutions. For instance, the W2K laptop that I'm currently using provides me with a 10ms timer resolution. My Solaris box provides me with a 1ms timer resolution. Other systems may only provide a 25ms timer resolution. Given the wide variation, what is a game programmer to do? The choices are, skip some frames or lower the quality when you are behind. You maybe surprised to hear that lowering a precision threshold is a common solution used not only in the gaming community. For statistical processes, it may not matter if your calculation is not perfect once you've considered the amount of error that may exist in the data. The point is that as programmers, we are taught to be precise and in most instances, this is good advice. But, there are certain instances when large gains can be made with a calculation that is less than precise with no loss of value.
Oh yeah, the second gotcha is that Thread.sleep() only changes the state of a thread to runnable once the sleep time has run out. This in no way means that the thread will run at that instant.
With this, we sign off on www.javagaming.org as we anxiously await the startup of the java.net site. Your efforts have been put to good use by Sun in it's new NIO package as well as some of the newer settings on the VM. To all of those gamers that have been an inspiration to this column I can only say thank you.
Back to newsletter 031 contents