PJ Feb. 23, 2001 I started digging into Java a bit, found out some stuff about Swarm and Java, why programs sometimes run slow. Here are some points. 1. Design programs that don't make many separate calls "across" the divide between languages. I had Java agents that were checking the system time with the call Globals.env.getCurrentTime(). I was also making a large volume of calls on the Swarm random number generators. These things slowed down my program. In Java that's slower to do these Swarm calls than in Objective-C because each call has to be translated through the connector between Java and Objective-C. Marcus Daniels wrote me this: "With getCurrentTime(), you're grabbing a SwarmActivity in Objective C from Java. With a random numbers, its the Objective C generator. You've got to consult the object yellow pages to figure out what Objective C object is associated with the Java interface you're using -- that takes some time. When it is in the middle of a loop (pj: like with the example class NSelectPJ, a Java implemention of the Swarm NSelect class that I had put together) that overhead adds up...." "The reason an object yellow pages is needed is that otherwise all the objects and their proxies would need to store their peers as ivars. With Java, say, that would mean either inheriting all objects in a simulation from some base class or modifying the VM to do it behind the scenes. The former is not transparent to the user, and the latter will have portability problems. This is not to say it isn't worth it, just that the most conservative thing was to do it `out-of-band' in a separate table, and I did the most conservative thing first. The macros that handle these things are set up in such a way this object-links-in-ivars approach could certainly be added. Without this enhancement, the way to avoid these costs is to structure things such that one-shot calls from a foreign environment (e.g. Java) are rare. Some ways to do that are to use features like the ForEachHomogenous callout ...." If you promise that a class is homogeneous, and use the forEachHomogeneous syntax, then one cross-language lookup is done, and the information obtained is applied to each successive case. In that case, the Swarm side in Objective-C finds out what Java method to use. 2. For the same reason, consider writing native Java "spaces" and containers for models in which agents move around. The fast heatbugs code substitutes a pure Java space, on the grounds that the cross-language calls are reduced. If one is careful in designing that Java class, it speeds things up entirely. 3. The Activity library--which has "scheduling" stuff--is the heart of the Swarm toolkit. It is one of the key reasons why Swarm is needed at all, because the diverse actions of many agents can be synchronized in discrete time. 4. Sven Thommesen pointed out to me this weird thing about integers. In C, there are unsigned integers, but there is no such thing in Java. So they get translated in a way that seems confusing, and is a potential source of trouble. Observe, the translation is discontinuous: Sven wrote "be aware that the mapping from objC unsigneds to java signed ints, (which happens automatically in the Swarm interface code) while linear, is not monotonic. It goes like this: ObjC Java ¯------------------ 0 -> 0 2^31-1 -> 2^31-1 ¯------------------ 2^31 -> -2^31 2^32-1 -> -1 ¯------------------- "Notice the flip from 2^31-1 t- -2^31 on the Java side. This means that code on the ObjC side of the sort "if (var1 < var2) {}" may give different results in Java than it does in ObjC. "Oh, and the problem happens in reverse as well. For example, generators take unsigned ints as seeds in ObjC and to explore the full range of possible seeds you'd need to use negative numbers as well in Java." Along those lines, Sven also said:"As you know, in ObjC the generators provide random variates in the form of doubles [0.0, 1.0) or unsigned integers [0, max-1]. For 32-bit generators, "max" may be as high as 2^32-1. For 31-bit generators, "max" is less than 2^31. Unfortunately, Sun designers in their wisdom decided to equip java with *signed* integers only, in the range [-2^31, +2^31-1]. Consider the fact that the underlying random generators in Swarm are written in ObjC. So when a Java program calls a 32-bit generator (such as the default one), variates that exceed 2^31 will map to a negative number in Java. (31-bit generators are not affected by this issue.) If your simulation expects a positive random integer, you might want to throw away all negative variates in Java. (And if you want the ObjC and Java sims to run the same, you'd want to throw away variates larger than 2^31 in ObjC as well.) Doing this will of course have unknown effects on the quality of the random streams you end up using. Or, use only the floating point variates from the generators, and map those to integers as needed." 5. Profiling Java applications. It does not work in JDK1.3 on Linux, but JDK1.3.1 does work. The usage "javaswarm -prof program-name" gives "old style" profiling information that is saved to a file, while "javaswarm -Xprof program-name" gives new style output to the command line and the Xrunhprof gives more sophisticated output. (You get the same output from -Xrunhprof:cpu=old as with -prof, but neither is very good on JDK1.3.1. 6. debugging. How do you set breakpoints with java swarm programs? You can't with gdb. You have to use jdb for Java-level breakpoints. In gdb, you can still stop any Action dispatch, as described, whatever language of the method. MGD added "To run JDK under GDB with profiling, you'll probably have to do some magic like this: handle SIGUSR1 nostop noprint Or just use a sourceware JVM like Kaffe that can be directly debugged."