Let Me Check That Out
Jul. 8th, 2019 04:46 pmWe had some code that was running slowly across a list of some 20K members. It turns out that the reason it was running slowly was that rather than just adding new members, we checked each member of the list to make sure that we weren't adding a *duplicate* member with the new add. This works fine for short lists, but is pretty much abominable by the time you're adding 20K members.
"Well," I said to myself. That's easy enough to fix. I can just add a hashCode() (and matching equals()) method to the class for the members that are being added to the list; then add a HashSet to keep track of what's already in the list, because that will look things up in a hurry. In fact, we should just make a class that welds a HashSet to the side of our ArrayList, because I know I've solved a similar problem before and we may as well not have to *keep* solving it."
I then paused and ran a brief search.
Right. ListOrderedSet in Apache Commons. I figured someone else had had this problem before...
Did I mention how nice it is to be working in a language with modern libraries available?
"Well," I said to myself. That's easy enough to fix. I can just add a hashCode() (and matching equals()) method to the class for the members that are being added to the list; then add a HashSet to keep track of what's already in the list, because that will look things up in a hurry. In fact, we should just make a class that welds a HashSet to the side of our ArrayList, because I know I've solved a similar problem before and we may as well not have to *keep* solving it."
I then paused and ran a brief search.
Right. ListOrderedSet in Apache Commons. I figured someone else had had this problem before...
Did I mention how nice it is to be working in a language with modern libraries available?
Refactoring
Mar. 26th, 2019 10:23 pmSo I'm working on a project at work where I'm porting some more C++ code to Java. I looked at the original code and said, "Well, let's see if we can streamline that." And I wrote a set of classes to support the behaviors that I wanted and which would generate the XML that I needed that C++ had been handling by writing exquisitely hand-crafted XML.
And I looked at the classes and said, "That could be simpler." And so I refactored the class structure I had written.
And I looked at the classes and said, "That could really be simpler." And I refactored the class structure into a set of Java enums.
It's a lot simpler now. :)
And I looked at the classes and said, "That could be simpler." And so I refactored the class structure I had written.
And I looked at the classes and said, "That could really be simpler." And I refactored the class structure into a set of Java enums.
It's a lot simpler now. :)
Changing the Subject
Sep. 20th, 2018 06:42 pmSo, meanwhile, back at work, I think I have gotten the last bugs out of the Java side of what I was working on. Now, I just need to figure out exactly how to port all of the fixes back to C++, where the code is "similar", but not "identical". It's that difference between the two that makes porting so much fun!
Hack and Slash
Apr. 12th, 2018 10:37 pmWe've picked up a highly dimensional client file for testing here and have discovered that the calculations are running a good bit slower than they were in older versions of the product. Part of this is due to the fact that I eliminated a number of direct pointers in favor of map lookups, because I was told that maps would be very, very fast in our Java code. Well, maybe they are faster in Java than they are in C++, but they are still not fast enough in either case, because the calculations are way too slow.
So I've been putting back in various bits of caching in both the C++ and the Java code. With nothing cached, the calculations were taking a minute and 47 seconds. Caching two data items cut the time to 1:25, which was respectable, but still slower than I had in mind.
I have now cached a third bit of interesting data and have cut the calculation time down to 57 seconds.
This is good.
Tomorrow, I'll finish this up and try caching a fourth and final bit of data and we'll see where we end up. :)
So I've been putting back in various bits of caching in both the C++ and the Java code. With nothing cached, the calculations were taking a minute and 47 seconds. Caching two data items cut the time to 1:25, which was respectable, but still slower than I had in mind.
I have now cached a third bit of interesting data and have cut the calculation time down to 57 seconds.
This is good.
Tomorrow, I'll finish this up and try caching a fourth and final bit of data and we'll see where we end up. :)
Cache On the Barrelhead
Apr. 4th, 2018 10:58 pmI've been cleaning up one of the subsystems in our product (that I did not write) and it is now substantially faster than it was. Aside from the earlier improvements I made in it, I taught it to cache two values that my version of this particular subsystem has cached since it was written. Doing this took the execution time to retrieve and write to a text stream a grid of nearly 700,000 cells from about 35 seconds down to 19 seconds.
There's other code that's running that is still taking way too long too execute, but this particular subsystem is now running much better.
There's other code that's running that is still taking way too long too execute, but this particular subsystem is now running much better.
Time, Time, Time, See What's Become of Me
Apr. 3rd, 2018 10:43 pmIt's back to the optimization grindstone for me after discovering yesterday that one of the optimizations that I put in that seemed to work really well was broken -- which was why it worked so well! I'm having a lot of difficulty improving the rendering performance by optimizing my code further. Of course, I've managed to improve that bit by fixing up not just my code, but some of the rendering code on our side of the fence to the tune of about a 37% improvement. This isn't good enough, but I'm starting to suspect that a good bit of the rendering delay is due to some change on the other side of the fence here. We'll see.
Meanwhile, today's early optimizations have improved the calculation speed by about 11%.
I can do better than that. I still know where the bodies are buried...
Meanwhile, today's early optimizations have improved the calculation speed by about 11%.
I can do better than that. I still know where the bodies are buried...
Not As Fast As You Intimated
Mar. 27th, 2018 10:38 pmWhen I ported all of our C++ code over to Java, one of the things I was told was "You don't have to worry about the speed of looking things up in hash maps. They're really fast." And since maintaining shared references to a single copy of an object was a pain in the butt, I started storing keys to the objects and looking them up in a master hash map for each of the different types of objects.
Then I found out that I was spending too much time looking up some of the things in the hash maps. So I made sure that the keys for the most frequently accessed object were immutable and shared via a common cache. And then I stored the pre-computed hash code inside the key, because not having to hash the key every time would speed up the searches a lot.
But the C++ code was running too slow, as I'd replaced the old shared pointers there. So I did the same trick in C++ that I done with the shared immutable cached keys with the pre-computed hash codes. Still not fast enough though.
Well, there was this value that I had previously pre-computed and stored, but was now looking up on the fly in a hash map with potentially multiple checks per value. Let's try putting that stored value back and only updating it when it needs to be updated.
Yes, that is fast enough.
*sigh*
Then I found out that I was spending too much time looking up some of the things in the hash maps. So I made sure that the keys for the most frequently accessed object were immutable and shared via a common cache. And then I stored the pre-computed hash code inside the key, because not having to hash the key every time would speed up the searches a lot.
But the C++ code was running too slow, as I'd replaced the old shared pointers there. So I did the same trick in C++ that I done with the shared immutable cached keys with the pre-computed hash codes. Still not fast enough though.
Well, there was this value that I had previously pre-computed and stored, but was now looking up on the fly in a hash map with potentially multiple checks per value. Let's try putting that stored value back and only updating it when it needs to be updated.
Yes, that is fast enough.
*sigh*
Bugs, Mr. Rico!
Jan. 23rd, 2018 11:06 pmI have been head down in bugs for the last two days since I came back from Confusion, dealing with nasty interactions between MFC in C++ and interoperable code in Java. I think that I've managed to sort out the nastiness, although it was disconcerting to find a big fat bug in a built-in Windows method.
*sigh*
*sigh*
On the Drift
Nov. 29th, 2017 06:28 pmI have just finished porting a big chunk of code from our Java implementation back to our C++ implementation.
I swear that the thing that will kill me is the continuing drift between the two implementations. There are many lovely new methods that I have coded in Java that had to be ported back to C++ so that I could call them there. And in Java, it's an OK thing to return a List<Something>. In C++, you want to create a CArray<Something*> and pass the reference into the method that in Java is returning a List<Something>. So the method signatures get screwy as you copy code back and forth. And "." turns into "->" or vice versa.
Eventually, I also need to clean up the variant versions of the camelCasing between the two implementations so that the old C++ IsSomething() ends up being the Java-style isSomething() on both sides of the great divide. As it is, the Java code is partially converted to the new style, as is the C++ code. But not all of the same methods have been converted on both sides.
And then there is "const". I love "const" in C++. I don't have it in Java. But I have immutable classes there that I don't have in my C++ implementation.
All of this is a recipe for a great thumping headache.
I swear that the thing that will kill me is the continuing drift between the two implementations. There are many lovely new methods that I have coded in Java that had to be ported back to C++ so that I could call them there. And in Java, it's an OK thing to return a List<Something>. In C++, you want to create a CArray<Something*> and pass the reference into the method that in Java is returning a List<Something>. So the method signatures get screwy as you copy code back and forth. And "." turns into "->" or vice versa.
Eventually, I also need to clean up the variant versions of the camelCasing between the two implementations so that the old C++ IsSomething() ends up being the Java-style isSomething() on both sides of the great divide. As it is, the Java code is partially converted to the new style, as is the C++ code. But not all of the same methods have been converted on both sides.
And then there is "const". I love "const" in C++. I don't have it in Java. But I have immutable classes there that I don't have in my C++ implementation.
All of this is a recipe for a great thumping headache.
Mix and Match
Nov. 13th, 2017 11:27 pmTrying to keep code that is in both Java and C++ in sync is starting to drive me slowly insane. The problem is that the two development environments that we're using (the standard Java libraries plus a lot of Apache libraries for Java vs. mostly MFC for C++) have ways of doing things that are just different enough to make things really difficult.
I am considering this problem. No great ideas yet. I think...
I am considering this problem. No great ideas yet. I think...
I'm finally gaining a bit of traction on the current project at work.
Mind you, today I took a side trip to convert the caching of a couple of ID classes from being model-based to being server-based. But this will be a good side trip to have taken.
And I have now written the first of the classes for the project that will actually do something as opposed to being boilerplate and necessary utilities to make things run.
So it's progress. Maybe not as much progress as I would like, but progress.
Mind you, today I took a side trip to convert the caching of a couple of ID classes from being model-based to being server-based. But this will be a good side trip to have taken.
And I have now written the first of the classes for the project that will actually do something as opposed to being boilerplate and necessary utilities to make things run.
So it's progress. Maybe not as much progress as I would like, but progress.
Lightening the Memory Load
Mar. 16th, 2017 11:50 pmWell, I added caching for another couple of classes today, which should reduce the memory footprint a bit further. Unfortunately, I am getting close to the point of diminishing returns.
The thing that's the real killer is a big doubly-linked list. Unfortunately, it's a big doubly-linked list that I really need.
*sigh*
The thing that's the real killer is a big doubly-linked list. Unfortunately, it's a big doubly-linked list that I really need.
*sigh*
Here I am, in the maze of twisty passages, all alike. Again.
When we open one of our models on the Java side, the memory usage in the JVM goes up by 200 MB. The heap dump says that the data associated with the model is only about nine MB.
Where the heck is the other 191 MB coming from? You'd think it would be easy to figure this out, but so far, not so much.
*sigh*
When we open one of our models on the Java side, the memory usage in the JVM goes up by 200 MB. The heap dump says that the data associated with the model is only about nine MB.
Where the heck is the other 191 MB coming from? You'd think it would be easy to figure this out, but so far, not so much.
*sigh*
So we're studying heap dumps for our Java app to try to determine why our models are taking up as much space as they are. After staring down some of the models, I dropped in a bit of new code.
The model that I was working with -- one of the smaller ones, admittedly! -- shrank by almost 10% in its memory footprint. Larger models probably won't shrink quite as much, but it was a gratifying result.
Now to see if I can use this trick in some other places. :)
The model that I was working with -- one of the smaller ones, admittedly! -- shrank by almost 10% in its memory footprint. Larger models probably won't shrink quite as much, but it was a gratifying result.
Now to see if I can use this trick in some other places. :)