Wednesday, September 30, 2009

Ant Task to generate GWT Classes and servlets

Yet Another Ant Task.
I made a task which given:
A source dir, a source classpath, and destination dir,
A series of source interfaces and a new GWT name,

My task will generate all the GWT plumbing. Namely the Service interface, the ServiceAsync interface, and a Servlet Implementation. If you specify a delegate, the the servlet will implement the interface by calling the methods in the delegate.
Pretty sweet.

I learned a lot about how "Generic" info about classes can be obtained through the reflection API. You might think that all the type parameter stuff is erased, a-la
Section 4.6 of the Java spec., but it is all there in the class, available through reflection. On the other hand, this leads to a paradox, because the it's not supposed to be there.


For example, let's say you have:

public interface Foo{
List<String> someMethod();
}

The compiler halts with an error if you try to implement Foo with this class:

public class Bar implements Foo{
List<String> someMethod(){return new ArrayList<String>();}
}

Because the type parameter of the returned List<String> has been "erased", and the return type in the interface is actually just List.

But if you were using reflection to generate class source you would still find the <String> type parameter. So to get your implementation to compile, you must discard the Type info.

At least that's the way it seems to work :)

Thursday, September 24, 2009

How to make JNI apps reloadable

JNI has this annoying "feature" , that makes is very difficult to run an application ( or ant task, or whatever) that loads a native library.
When you load a class ( lets call it Foo ) that loads loads a DLL, loadLibrary is called on the ClassLoader that loaded Foo.
If you try to load the Foo class again, and the library is still loaded, then loadLibrary will fail with a java.lang.UnsatisfiedLinkError.

The DLL that Foo loaded will NOT be unloaded when Foo is garbage collected. The DLL will not be unloaded until the ClassLoader, and all the other classes that were loaded with Foo's ClassLoader are garbage collected. If that ClassLoader is the System ClassLoader, it will never be unloaded while the JVM is running.

This makes it an exceptional pain to try and re-deploy an app to an application server.
There is a lot of whining about this, and a lot of bad advice. So here is a WORKING solution.

A) All the classes that load native libraries (JNI clients) should implement interfaces for their use.
B) All the other classes should ONLY reference the interfaces, never the classes themselves.
C) JNI client classes must be loaded by a separate classloader then the other classes.
D) The instances of the JNI client classes must be instantiated by reflection, not by directly calling a class’s constructor. This prevents the class being loaded by a non-JNI ClassLoader

To accomplish this, I created a VolitileFactory class, that subclasses URLClassLoader. It has a makeInstance method, which loads the JNI client classes, and invokes the correct constructor via reflection. The VolitileFactory instance is a field of the Anchor class. Anchor has static methods to obtain implementers of the JNI client’s interfaces. Anchor holds the only reference to the factory. When the app shuts down, that reference is deleted, System.gc() is called, and the libraries unload.

Saturday, September 12, 2009

Summer break is over, back to the Toy.

I re-implemented the event loop and the event objects to be in Java instead of native code.

There is a Java EventMachine. A client uses getTheEventMachine to get only instance. It maintains a timer and a FIFO blocking queue of SimpleEvents. SimpleEvents are added to the queue by the addEvent method of EventMachine. At the preset interval, the queue is locked, and the SimpleEvents in it are dispatched to processEvent in the UpperDeck one at a time, until they are all processed, or until a set amount of time has passed. Then, dispatching ceases and the queue is unlocked. processEvent in UpperDeck processes the event, and in a finally clause, calls the delete method of the event.

This system is used by native code via a C++ JEventMachineConnector class. This maintains a global reference to a thread in the EventMachine where addEvent executes. So when addEvent is called on JEventMachineConnector, it joins the Java thread, calls addEvent on EventMachine, and upon completion, detaches from the thread.

The SimpleEvent interface is an immutable collection of three properties: source, type and message, and a delete method. However the implementation of SimpleEvent is not simple. An implementation consists of a Java object SimpleEventJavaImpl, and it’s native shadow. The Java object implements SimpleEvent, exports a delete method, and maintains a pointer to the native shadow object. This delete method is actually implemented natively. Upon garbage collection, if the native resources have not been freed, SimpleEventJavaImpl calls its own delete method. The native shadow object maintains a link to the Java object, and native versions of the initial value of the properties of the SimpleEvent. It also implements logic to create SimpleEventJavaImpl objects from the native side. The hairiness of SimpleEvent implementation comes from the logic to instantiate one from the native or Java side, and then to delete all native resources.

The Toy also grew much hair implementing Java<->Native exception handling, and other error management. I learned far more then I wanted to know about C++ templates, Unicode on Windows, and why the C++ preprocessor is pure freaking EVIL.

Wednesday, June 24, 2009

Passing wrapped C++ objects to Java

In the Toy, C++ code generates an Event, and passes it to Java for processing.
The flow is
Client class (Cclient) creates C++ SimpleEvent (launchEvent)
cClient calls getJEMConnector()->addEvent(*launchEvent);
addevent attaches the C++ thread to the JVM,
creates a Java SimpleEvent wrapper (jSimpleEvent)
calls addEvent(jSimpleEvent) on the Java EventMachine

An now it's up to Java to further handle the event.

Object life cycles are tricky when there are multiple threads. Calling a Java constructor from C++ is no fun because of the weird signature stuff, i.e. "", "(JZ)V" to call the constructor that takes a (long)pointer and a boolean argument.
Then there is Local/Global reference issue. DeleteGlobalRef must be called within C++, before the object is destroyed, on some JavaENV, that should have been cached earlier. This is on top of the memory management problem, as discussed earlier.

I'm going to do some memory leak checks now. I'll be surprised if there are none, because nowhere in C++ do I call DeleteGlobalRef for the SimpleEvent wrapper.

Monday, June 22, 2009

Allocate objects from the JVM

My Event and threading mechanics are all going to be in Java. But I still create some events from C++, wrap them in a Java class, and add them to the queue. When they are processed, I destroy them, and clear the queue, so there are no references.

This created a memory management problem. The "new" was in c++, but the "delete" is in Java. So I ended up overriding the new and delete operators, and having them use the JVM for resources. This seems to work.

Saturday, June 20, 2009

Note to self, varargs stuff are all macros

So, I leared how to use varargs.

Not just declaring a varargs function and getting the arguments.
No, the trick was to get a va_list and pass it on to something like vswprintf. My problem was that whenever I had a number in my va_list, it would get scrambled in the output.

The thing to learn was that all the varargs stuff is just pointer arithmetic on a single char *, obfuscated by macros. The macros create hidden variables, which change state on every use of va_start(), va_arg(), va_list(). So, you can't use any of the arguments passed to your function if you want to pass that va_list on to another function. If you ever call va_arg(), you must reset everything bay calling va_end(), va_start() before you pass the va_list.

It's pretty rotten that
A) None of this stuff follows macro naming conventions, i.e VA_START
B) The side effects of using va_start and va_args are undocumented, not even on faqs or forums.

Wednesday, June 17, 2009

Debugging's "attach to process" broke.

Somehow,
Attach to process from "java.exe" does not work since I reinstalled everything.
"java.exe" gets expanded to the the full path, Q:\sdk\jdk1.6.0_14\bin\java.exe

Which does not match the process in the process list, as launched by Netbeans.

It used to work, but now instead of just hitting f5, I must use two menus, search and click. Visual Studio is simply terrible. How can a product with so many iterations stink so bad?

...
Anyway the trick to getting f5 to work again was to use
Q:\sdk\jdk1.6.0_14\jre\bin\java.exe

Note the "jre" in there.

Sigh. For whatever reason , MSVC stores this debugging info on a
per-user level, with not even a shadow in the project's .vsproj XML file.

So there is no easy way to store this setting with the project.

Tuesday, June 16, 2009

Mercurial Trap

I really like mercurial.
One of the great things is that you have local and "other" (remote) repositories. You can happily check in and track changes locally, then later, push your changesets to the remote repository.
But this leads to a usability issue. You can *forget* to push your changes, and you can neglect to have a remote repo at all.
This just happened to the .swg I made for SWIG. When my drive was corrupted, I lost the work I had done. In this case it was only a few minutes to re-create it. But it could have been bad.

Mercurial does allow practically unlimited extensions, so I could make mercurial automatically create a remote repo when I create a local one. I could also make some kind of nag feature for pushing every day or something.

Build environment

Just for reference, here are the tools and libraries that need to be installed.

*** Tools ***
Netbeans 6.5+
MSVC 2008
Ant 1.7+
CUDA 2.2
Mercurial 1.2+
swigwin (customized!!)
boost-build

*** Libraries ***
jargs
jinvoke
CUDA 2.2 SDK
freeglut (customized!!)
boost_1_38_0 (with static+multithreaded+debug compilation)

*** Projects ***
filesystemmanagement
JNIAntTasks

Friday, June 12, 2009

System woes.

Diskkeeper corrupted my filesystem.
Prudence means that I have a remote repository, and that I've only lost a day of changes, but that assumes that ONLY my local repo is damaged, and not any of the other files (binaries!!!) on that volume. I expect that there is corruption all over this drive, and I must reinstall EVERYTHING. This sucks.
I am looking a one hell of a lot of stuff to download and install.

The week of work that I have not posted about was a new Java based event system. To get this to work, I installed SWIG, a general purpose c/c++ -> other language integration tool. But strangely enough, SWIG does not support unicode for Java, and so I had to mess around for a day creating a SWING typemapping file. ick!

It works, but then my filesystem was corrupted by Diskeeper.

Thursday, June 4, 2009

Now I need a whole new event-loop.

ImageFactory works.
I had to customize FreeGlut to share the HWND window handle that it creates when it opens the main Window. From that I can call wglCreateContext and make that rendering context current. I'm not sure how to get OpenGL rendering context without ever opening an Window....
Anyway, ImageFactory is now dependent on data that must be requested from the UpperDeck, but I've run into insurmountable system-messaging bugs.

Currently, the Toy uses FreeGlut to manage windowing, keyboard, etc.
I am now convinced that the main-loop of Glut breaks Swing, and maybe all Java events. I suspect that the system messages are held up somehow, and are only passed along after the "main window" closes.

The irony is that I'm not going to use the FreeGlut main loop, Swing, or even a screen window. But for testing etc, I need a GUI for control and communication.
So I have to dive into replacing the main loop before I wanted to.
Dang.

Oh, and there are still bogus exceptions thrown from within the Nvidia drivers at "exit". These propagate up and crash the JVM.

Dang again.

Friday, May 22, 2009

Bogged down in driver bugs

I have not made progress in the thread context stuff because of driver crash bugs.
Luckily, CUDA 2.2 just came out.
So I installed the new drivers, toolkit and SDK, and ported my source code.
Things are now MUCH better. Even though there are still many "first chance" exceptions, at least I don't have the same show-stopping crash bugs.
I can now return to the re-writing ImageFactory to have its own GLContext.

Tuesday, May 5, 2009

OpenGL is very particular about threads.

So, it turns out that every thread that uses OpenGL needs its own rendering context.
Currently, the thread running in the ImageFactory class does not have one. Let's call that thread imageProducerThread.
This means that I must either:

Join the launch thread from imageProducerThread,
Create a new context on imageProducerThread,
Move all the OpenGL stuff to imageProducerThread,

All of these require lots of re-writing....
Sigh, I guess moving everything is the best solution.

Dang.

Friday, April 17, 2009

Ready to learn about glReadPixels, DIBs and GTK+

My event infrastructure seems complete and functional enough.
I tripped up by putting calls to java.util.Logging in the event thread. It would be nice if Sun had documented that those methods are not thread safe.

Now I need to get my rendered images out of the CUDA environment and into a bitmap.

I Posted on the openGL forum and got some hints, so here I go!

Friday, April 10, 2009

Ignorance and distraction.

The problem was that alock did NOT drop out of scope in the code as written.
alock was also defined out of the if block, and only gets its value in the if block.

I deleted the declaration and now the line
boost::mutex::scoped_lock alock(_mutex);/*Yes Charlweed, lock is an INSTANCE.*/

Works as expected.

Behold! The power of ignorance

It's looking like the bug has nothing to do with JNI.
I don't really know much about C++ threading, the Boost APIs or even STL. So I don't yet see the fundamental flaw in this event loop:

while(true){
if(!_eventList.empty()){

boost::mutex::scoped_lock alock(_mutex);/*Yes Charlweed, lock is an INSTANCE.*/
for(eventIterator =_eventList.begin();eventIterator != _eventList.end();eventIterator++){
/* pop the event off of the queue */
queuedEvent = &(*eventIterator);// This line really bugs me.
//processEvent(queuedEvent,javaThreadEnv,theUpperDeck);
}
_eventList.clear();
}
}


It does not work at all. Because this is running on a separate thread, I want it to flow forever, PAUSING only when it cannot get a lock on the mutex. I'm not sure what is really happening, but it looks like the other thread blocks permanently after the _eventList gains an item.
Dang.

Threading Bug?

As I said before, I created functionality where the DLL can post a string to the Java app. My problem is that if I log that message with the java logger, or try to show it on the screen in Swing, the message:
a) Fails to show the string.
b) Stops the flow of control.

I’m not saying things like “deadlock”, "blocks" or even “hangs” because I don’t really know what is going on.
Within my display method in Java,
SwingUtilities.invokeAndWait
and
SwingUtilities.invokeLater
completely hang, both with threads and runnables.

I tried starting a new thread but that fails too.

Now I'm going to read the chapters on “Monitors” and “Exceptions” to see what exotic BS might be going on.

Speaking of exceptions, I found that yes indeed, the native code is completely swallowing my exceptions from within Java. So the bug above is really hard to diagnose.

Thursday, April 2, 2009

The important part is...

So yeah, my native code can now communicate with the Java App :)
Yea!

The way do do this is to call any method of
 com.hymerfania.mandelbrotbridge.UpperDeck 

from within the switch block of

MandelbrotLib::EventMachine::processEvent


Right now I have merely hard-coded a call to
 UpperDeck.helloWorld(String message)

But I could register listeners on UpperDeck, and propagate events out from there.

I'll wait on that, because I don't what I want to transmit out of the DLL, or who will want to listen.

Event model works.

It turns out that SwingWorker is not enough to run native code.
I had a terrible time figuring out why SwingUtilities.invoke* would not launch my runnable.
What I was doing was

MainThread runs starting the mainApp
SwingThread runs gui
SwingworkerThread runs some setup code but...
propertyChangeThread runs the nativeDLL

The nativeDLL calls back into java. That java code attempts to use java.awt.EventQueue.invokeLater to make changes to the GUI. Well, it seems that you cant use EventQueue methods from the thread that propertyChanges are on. Note that whatever the propertyChangeThread actually is, it is NOT the Swing Event Dispatch thread. I checked for that.

Anyway, I created and started a completely new thread to run the DLL code, and everything seems to work much better.

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.