Monday, March 30, 2009

Perfectly bad example

This is the example that I wasted the morning on
 
struct count {

count(int id) : id(id) { }

void operator()() {
for (int i = 0; i < 10; ++i) {
boost::mutex::scoped_lock lock(io_mutex);
std::cout << id << ": " << i << std::endl;
}
}

int id;
};

This example came with no explanatory text. Not only are there advanced C++ goodies like initialization lists and functors, the guy uses the c++ idiom where same identifier is used for a formal parameter and a field variable. The compiler gives you a clever wink when you use code like

id(id) { }


and sets the field "id" to the argument supplied in the constructor "id".

This example should have the comment
/* If you are reading this example, you are too ignorant to use my code. Go away. */

Functors as Runnables

I encountered

void operator()(){/* work here */}


As a pattern in c++ threading examples, but I could not read it. It was really hard to figure out, because "()()" is not a an indexable string. This means that not only can you not search for it online, it does not appear in the index of paper C++ reference manuals either.

I knew that this code is overloading the function operator, but the term "function operator" is almost never used to literally refer to the c++ function operator. So searching for combination of "overloading the function operator" was fruitless.

Finally, I found the Wikipedia page on STL, which included

"The STL includes classes that overload the function operator (operator()). Classes that do this are called functors or function objects. They are useful for keeping and retrieving state information in functions passed into other functions. Regular function pointers can also be used as functors."

This was enough of lead to find enough info.

A class that overloads the function operator ( a functor ) allows one to use instances of that class anywhere you would want to use a function. In particular, you can pass a functor instance to something, and that something can "run" that object. It is effectively similar to "Runnable" in Java.

Sunday, March 29, 2009

The quagmire

In order to communicate asynchronously back to Java from a native DLL, I need an event infrastructure.
To build an event infrastructure, I need a lockable (thread synchronized ) queue.
Boost.Thread seems to have what I need, but first I need to install and configure it.
Then I need to figure out that the pre-built binaries are missing one of the static libs, so I need to download and build boost from source.
Then I need to download and build Boost.Build and bjam.
Then I need to figure out that Boost.Build is not the sources for boost, but is just the build tools.
Then I need to download the correct sources, but that meant I have to wait 27 minutes for a 56mb download.
Then I need to configure the source build, and run it. A working config meant a Google hunt. The build took at least 1:15, and 1.46 GB.
……
Ok,
#include boost/thread/shared_mutex.hpp

No longer breaks my build, now I have to figure out how to use the boost threading library….

Thursday, March 26, 2009

JNIEnv is only good for the duration of a Java->C++ call

I was trying to make JNIEnv a property of a C++ class, stored by a singleton.
This can't work, because JNIEnv is only valid for the duration of a Java->C++ call.
Apparently each instance is related to a particular Java thread.
Super bummer. Now I must figure out a new way for C++ to call into a running Java process.

And I was feeling so good about my clever Ant task that could insert user-defined source code into the body of generated JNI glue functions....

Monday, March 23, 2009

Detour

There is very little tool support for C++ calls into a Java app. So I had to write a tool to generate c++ implementations, as opposed to just declarations in header files. It's an Ant task, javacpp, not a stand-alone tool, and it takes Java declarations like this:

public native void setUpperDeck(UpperDeck theUpperDeck);

public void addPropertyChangeListener(final java.beans.PropertyChangeListener listener) {
_propertyChangeSupport.addPropertyChangeListener(listener);
}

And generates c++ code like this:

JNIEXPORT void JNICALL Java_com_hymerfania_mandelbrotbridge_UpperDeck_setUpperDeck(JNIEnv *javaEnv, jobject javaObject, jobject somejobject){
jclass thisJavaClazz = javaEnv->GetObjectClass(javaObject);
jmethodID mid = javaEnv->GetMethodID(thisJavaClazz,"setUpperDeck","(Lcom/hymerfania/mandelbrotbridge/UpperDeck;)V");
/* insert your code here */
}

JNIEXPORT void JNICALL Java_com_hymerfania_mandelbrotbridge_UpperDeck_addPropertyChangeListener(JNIEnv *javaEnv, jobject javaObject, jobject somejobject){
jclass thisJavaClazz = javaEnv->GetObjectClass(javaObject);
jmethodID mid = javaEnv->GetMethodID(thisJavaClazz,"addPropertyChangeListener","(Ljava/beans/PropertyChangeListener;)V");
javaEnv->CallVoidMethod(javaObject, mid, somejobject);
}

Friday, March 20, 2009

Event driven design

The way I am going to communicate is with events. I desperately hope nothing gets weird with thread management in JNI.
The property change stuff was easy, but I still don't have a mechanism for methods called from Java to post events back to the caller. The trick is going to be to create a Java object that C++ can grok. It looks like jInvoke only spares me half the pain of JNI.

Then there are threading issues. I think I may need my own event queue, I don't know if I can use the ones built into Java...

Wednesday, March 18, 2009

That trick NEVER works!

I created a java form to
A) Have a place to display data generated in the DLL
B) Suspend the flow of execution so that I have time to attach a debugger to the running processes.

Before I created functionality and infrastructure to pass back data from the native DLL, I wanted to take a stab at debugging the running code. I want to be able to just attach the windows debugger to a process that runs the DLL, but that is the kind of stuff that should work, but never does.

I started my java in the NetBeans debugger, and up popped my form with it's single button. From Visual studio, I attached the windows debugger to the running hava precess. When I clicked "Launch" it stepped through a couple of java break points, then called the native function.

Presto, the my first breakpoint at the entry function hits, and the Windows debugger opens.
"**** ****!" I say, "That's what was SUPPOSED to happen!" Now I can trace my goofy hack to convert a Java array of unicode Strings into C **char and pass it to the native code. More amazement, it has actually worked on the first try. Now I have to make it work The Right Way.

Listen to uncle Charlweed

Now Cillren,
Yu listen-up up to uncle Charlweed.
Don' yu evah, EVAV, make actual file system directories with whitespace in the filename. No matta what no shreekin, droolin monkey in Marketing tell ya.
Yu give dem all da underscores, dashes, soft links, aliases, and short cuts dey want.

But if you release something with a directory actually named
"bin objs"

Well, den you deserve to be ********* ** *** ***** ** *** *******. And I'll lend 'em ol Billy here to make sure dey git ya good.

No console I/O, so I need two way communication.

I can't really tell if my arguments are being passed, because all the console IO goes into a black hole.

So I can
A) Create a dialog in win32 to show any output
B) Create a Java output object, and pass that to win32


Because I am going to need to do something like B eventually anyway, I'll try that first....

Monday, March 16, 2009

Calling from Java Code

It looks like a thing called jInvoke MAY be fantastic.
To review, I need to call my native DLL from java code. The old way of doing this was with a thing called Java Native Interface (JNI). Make no mistake, raw JNI sucks. Really, really, sucks.

Enter Java 1.5 and Annotations, to save the day. Some guys have come up with JInvoke, that seems to hide most of the ugliness of JNI. It is pretty opaque, but at least it's not pages of error prone crap that must be hand generated and maintained for every call. The hard part is type conversion. JInvoke cooks all the c++ signatures in a poorly documented way. So surprise surprise, lots of trial and error. Still, I got my "app" to launch from java, and I'm kind of amazed :)


Given a c++ declaration

MANDELBROTLIB_API int launch(int argc, char **argv)

Visual Studio creates a dll with

?launch@@YAHHPAPAD@Z = ?launch@@YAHHPAPAD@Z (int __cdecl launch(int,char * *))

This must be declared in JInvoke as
@NativeImport(library = "Mandelbrot.dll", function="?launch@@YAHHPAPAD@Z", charset = Charset.ANSI)
public static native int launch(int argc, int[] argvalues);

My first stab at faking int[] argvalues starting from an array of Java Strings is

String emptyArgs[] = new String[]{""};
int argVptr;
int[] jInvokeArgv;

argVptr = com.jinvoke.Util.stringToPtrAnsi(emptyArgs[0]);

jInvokeArgv = new int[]{argVptr};
launch(args.length,jInvokeArgv);

This does not crash anything, so it may be the right track at least.

Tuesday, March 10, 2009

Sucessful Launch

Yea!
My CUDA dll launches from a wrapper App.
At, during ( or after ?) exit, nvoglnt.dll is misbehaving:

"0xC0000005: Access violation reading location 0x00000770"

This is thrown as an exception. It could be a million things, starting with the fact that I've compiled for debugging.
If the call is in my dll code, I'm just going to catch and ignore it.

Command Line arguments in Visual Studio

In Visual studio, there is a bug that prevents command line arguments to passing to a debugged application if the project is NOT the "Startup Project".

) Select the project that has your main(argc, argv),
) Edit the "Command Arguments" property on the Debugging property page.
) Right click on the project and select "Set as Startup Project" from the menu.

Now when debugging, the arguments should be correctly passed to the application.

Many posters on MSDN ask about this bug, my post of this workaround was the first appearance of a functional work-around.

Sunday, March 8, 2009

C++ Microsoft Unicode "[Ss]trings"

Ugh, to get console output in a Win32 console application, you use outputdebugstring. The trick to getting it to actually show up in Visual Studio is by having a window named "Immediate Window" open and focused. Of course, this is un-documented. Well it was, I added a comment on the official MS doc page.

ANYWAY, I'm ready to dll-ify the Mandelbrot application. Ro use CUDA and to be interfaceable with other platforms (Java etc.) My Dll must be plain c++. No C# or other reasonable languages. I feel the dread.

I figured out how to get what looks like a dll and an exe from the same solution build. Now, to make it linkable, I must replace the main(int argc, char** argv) function in the Mandelbrot application with something with a different identifier, and with (int argc, _TCHAR* argv[]) parameters.

This stinks. Because of all the macros, templates, and generics, I can't even tell what the hell a _TCHAR is at compile time. So can't I know out which of the type specific conversion functions I might be able to use.

Wednesday, March 4, 2009

Visual Studio WTF?

The reference for the IDE "Visual Studio" is buried six levels deep in a mountain of thousands of topic headings. The name of the section is "Reference (Visual Studio)" Now that I've stumbled onto it, at least I can bookmark it.
Even from here, simple essential stuff is practically impossible to find.

)Why can't I add DLL references to my project? The IDE will only let me choose other projects.
)How can I have the console output of my program show in the output window of the IDE? ( outputdebugstring ??? ) WTF?

Hours, wasted.

MSDN Library

I did not intend this blog just to be a place to bitch about crappy development tools, but the nonsensical, painful-to-use designs of this stuff has literally wasted calender days for me.

At some point, I think it was Visual Studio 2000, Microsoft put all the online documentation for development tools, APIs, language specifications and everything into one "library". This pile of documents is MSDN Library. It was not a great idea, but not terrible.
What WAS terrible is that they shuffled it all together. So any single "page" can have stuff mixed together from all over Microsoft. The index is useless, and the help search is not merely "simple" it is perfectly moronic. Maybe there is a special syntax for searching MSDN library. Guess where that syntax would be documented?

Hey I just found it! That only took a week.

"Search Syntax

In previous versions, multiple word search strings, such as "word1 word2," were equivalent to typing "word1 AND word2", which returned only topics that contained all of the individual words in the search text. For this release, the search engine interprets multiple word searches as equivalent to "word1 OR word2", which returns topics that include any of the words in the search text. You can change the default search behavior to use the AND interpretation by unselecting the option Include partial matches in local search results on General, Help, Options Dialog Box.
"

Thanks, guys. :(

22,000 Frames per second.

Ok, I'm impressed.
I built the Mandelbrot demo, and even in debug mode, no optimizations etc, it reports
better than 20,000 frames per second.

I remember in university, single screens at lower resolution taking minutes to render ( say .01667 fps ). Moore's law gives an estimate of a 1024 fold performance since the mid 1990s. 20,000 fps is 1200000 times faster than .01667 fps, and so is 1171.875 times faster then the Moore's law estimate.

So any way you slice it, that's a Step Up.

Added new OS installation just for CUDA

So now my PC is multi-boot.
One XP partition is for normal use, has the old, good drivers, and cannot be used to develop CUDA. The other partition has XP with the new drivers, and can be used to develop CUDA. It's a waste of drive space, but when I originally built this machine, I reserved a partition big enough for an OS install. Sometimes pessimism is a good thing. If I had not already done this, adding a new partition would change my drive letters, and break tons of stuff.


I wish I could use a virtual PC instead of multi-boot, but I cannot install the required NVIDIA drivers on any virtual PC I know of.

Worst usability in decades

"Click Here to irreparably trash your System"
It's hard to imagine how any modern software company should ship a "utility" like NVIDIA's driver uninstaller. Wait, here is some context...

I can't use CUDA on my machine as-is. There is an incompatibility between my NVIDIA drivers and CUDA. This root of the incompatibility is not really technical, it's bad product management.

1) The only reason I have older drivers (175.19) is that NVIDIA stopped supporting my video cards. My twin 8800 GTS cards are less then a year old, and are SUPPOSED to be supported, but the last six months of drivers break SLI, and bluescreen crash often. Way to build brand loyalty guys. :P

2) CUDA 1.1 ( all I really need ) is SUPPOSED to work with my older drivers, but has been hard-coded to work only with Visual Studio (VS) 7 or 8, NOT gcc nor VS 9. CUDA WOULD actually work with both, because gcc is supported on Linux, Sun, HP, etc. and there is no difference between VS 7-8-9 as far as CUDA is concerned. But some idiot required that the tool check to see if it is running on Windows, and if the compiler is not VS 7 or 8, it exits with an error.

3) Switching between driver versions is explicitly broken. Deliberately or not, update and rollback are broken with NVIDIA graphics drivers. To install new drivers, you must use a custom utility to uninstall the old drivers.

This utility is the worst example of usability I have seen in 20 years.


The default option :
"Remove all NVIDIA drivers, except DISPLAY",
is the option used if you just hit return. If you try it, your computer is BRICKED. The utility uninstalls the chipset drivers, which makes your PC unable to use ANY of your hardware. That includes hard drives, USB, network, mouse, keyboard even memory. Once you hit return, you will have to reinstall the OS. Furthermore, you had better have the original installation media that shipped with the PC or motherboard, because otherwise you would even be able to do that. The second of the three options:
"remove all NVIDIA drivers"
also will brick your PC. Only One of the three options:
"remove display drivers"
will leave your PC in a workable state. And OF COURSE, this tool has no warning or confirmation of any kind. If you click the wrong box by accident, and click OK, you have just completely trashed your computer.
Did I mention that almost all games tell users to install new drivers before installing the game?

4) You cannot unpack more than one CUDA version on one PC. CUDA Tools and SDKs are distributed as self-extracting executables, even on Linux and Unix. When run, the executable not only "uninstalls" any previous version of CUDA, it erases the old CUDA from your hard drive. This means that changing to different versions of the API would be stupidly difficult, because the developer would not be able to compare the old version to the new. I say "would be" because the erase functionality is only half-baked, and all you need to do to defeat it is rename the old directory before running the installer. Still, this feature is idiotic.

All this ads up to NO-WAY to develop for CUDA on my perfectly good NVIDIA setup.

Starting project.

This project aims to create a fast easy-to-use Mandelbrot set viewer toy. It will use AJAX for the front end, and use CUDA on the back end for computation and rendering. Java2d will glue the things together.
Wish me luck.