Sunday, December 24, 2006

better watchout
better !cry
better !pout
lpr why
santaclaus town

cat >list /etc/passwd
ncheck list
ncheck list
grep >nogiftlist naughty list
grep >giftlist nice list
santaclaus town

who | grep sleeping
who | grep awake
who | grep bad|| good
for (goodness sake) {be good}

Happy christmas everyone.

Friday, December 22, 2006

On yet another new topic, i'm proud to have the first implementation of Mono.Nat available here. Mono.Nat is a C# implementation of the uPnP protocol implementing just the bits needed to forward a port from a uPnP enabled router to your computer. There are plans to implement the PMP protocol aswell, along with any other port forwarding type protocols that get devised in the future. The idea is that regardless of what kind of router you have, you'll be able to map a port with a 3 (or so) lines of code.

It comes with a code example showing you one way in which to use the code. But it is fairly self explanatory. It's as easy as: natDevice.BeginMapPort(12321, TCP); natDevice.EndMapPort();

If anyone has a NAT enabled router, i'd appreciate it if you could load up the TestClient (in the examples directory) and see if it will map and unmap the 4 different ports. If it does, then all is well. If not, then either tell me what the problem is, or try fix it yourself and send me a patch. It's all good :)

Thursday, December 21, 2006

For anyone interested in checking out the current status of XNA:

Wednesday, December 20, 2006

In a similar theme to my last post, i'm going to harp on about a much more useful and not so obvious performance boost i made:

Firstly, consider the following two method signatures:
M1: public static Matrix Add(Matrix matrix1, Matrix matrix2)
M2: public static void Add(ref Matrix matrix1, ref Matrix matrix2, out Matrix result)

From first appearances, which method would you expect to be faster? And why? I'll come back to that in a minute.

Now, the way the code was initially written is that all the logic to add two matrices was contained in M1. So if you called M2, internally M2 would just call M1 and return the result to you. That's fine. It's definitely a good thing to not write the same code in 2 or more methods! This code resulted in the following performance characteristics:
M1 called 5,000,000 times: 500ms
M2 called 5,000,000 times: 750ms

As you can see, contrary to what you might think, M1 was performing significantly faster than M2! Now, the reason why you would expect M2 to perform *much* faster is that passing by ref means that the Matrix struct will not be copied into a new stack frame. Instead a reference to it will be there (which is significantly smaller in size, therefore faster to create). However what was happening is that a reference was being passed to M2, then M1 passed a new copy of the matrix to M1. This meant that all the benefits of using ref were lost.

So, my quick change was to move all the logic to "Add" two matrices into the Matrix.Add(ref,ref,out) method. That way whenever anyone called M2, there would be no copying of structs done, thus potentially making the method much faster. Whenever M1 is called, it then calls M2 internally to do the actual adding, and returns the value then. This way of doing things resulted in the following performance characteristics:
M1 called 5,000,000 times: 720ms
M2 called 5,000,000 times: 200ms

As you can see, M2 is now *much* faster than M1, which is what would be expected when using ref parameters. Also, M1 is now a bit slower, due to the extra overhead of calling M2 to do the adding, but not significantly so.

Just as a reference, heres the same code running under Microsofts XNA:
M1 called 5,000,000 times: 670ms
M2 called 5,000,000 times: 200ms

If i really wanted, i could increase the speed of Matrix.Add(Matrix,Matrix) by writing the adding logic in there aswell, but i don't really want to do that. If you want performance, you'll use the Add(ref,ref,out) option.

The before and after code can be seen here
I started working on Mono.XNA today. For those of you that don't know what it is, it's a cross platform implementation of the Microsoft XNA framework. So in a good few months, it should be possible to write a game once and then play it on MacOS, Windows, Linux, Xbox 360 and if you're really lucky, the PS3 aswell.

At the moment i'm just getting up to speed on the status of things. There's been a little bit of implementation done, and a lot of class stubbing. My aim over the next few days is to run some tools over both the Mono.XNA libs and the Microsoft.XNA libs and start creating a chart of what has been stubbed, what has been implemented and what hasn't been touched yet. This will help both existing devs and new devs figure out what's going on.

I'm just going to finish on one important note which came to my attention when looking at some of the Mono.XNA implemented classes.

String arithmetic is bad!

I came across the following (single) line of code in the ToString() method of the matrix class. While i have to admit, it was technically right, i just had to get rid of it asap. Here's the line:

return ("{ " + string.Format(info1, "{{M11:{0} M12:{1} M13:{2} M14:{3}}} ", new object[] { this.M11.ToString(info1), this.M12.ToString(info1), this.M13.ToString(info1), this.M14.ToString(info1) }) + string.Format(info1, "{{M21:{0} M22:{1} M23:{2} M24:{3}}} ", new object[] { this.M21.ToString(info1), this.M22.ToString(info1), this.M23.ToString(info1), this.M24.ToString(info1) }) + string.Format(info1, "{{M31:{0} M32:{1} M33:{2} M34:{3}}} ", new object[] { this.M31.ToString(info1), this.M32.ToString(info1), this.M33.ToString(info1), this.M34.ToString(info1) }) + string.Format(info1, "{{M41:{0} M42:{1} M43:{2} M44:{3}}} ", new object[] { this.M41.ToString(info1), this.M42.ToString(info1), this.M43.ToString(info1), this.M44.ToString(info1) }) + "}");

Yes, that huge block of code was written in one single line. Now, the main problem with this code is not the fact that it was written in one line, but that the amount of strings and objects generated is HUGE. Far beyond what is needed.

Let me dissect it in a little more detail. As soon as that long line of code is hit, it generates (by my count) 24 instances of the string class and 4 object arrays. Now, as strings are immutable, every time you "add" a string, what happens is a brand new string is created in memory and the old string is dumped, waiting to be garbage collected. So, once you take the string.Format() calls into account, you have a sizeable amount of strings being created per call. The overhead in this is massive!

Now, what should've been done is a StringBuilder should've been used. This would have cut the number of string instances created right down to just 1 per call, along with a single instance of the stringbuilder class.

So lets whip out the benchmarking utils and prove my point.

Original Method:
With the original method being called 10,000 times we had the following stats from my profiler:
Allocated bytes: 21,699,068
Relocated bytes: 17,864
Final Heap bytes: 897,800

This method allocated a whopping 2.11 kB of memory per call to Matrix.ToString(), give or take. That's a *lot* of memory when all you want to create is a 100-150 byte string! The execution time was approximately 4.41 seconds.

StringBuilder Method:
I changed to code to use a StringBuilder with default capacity of 140 bytes and called it 10,000 times. This had the following stats:
Allocated bytes: 6,479,100
Relocated bytes: 8,764
Final Heap bytes: 254,218

As you can see, this method reduced memory allocations by 66% straight off. The average memory allocation per call to Matrix.ToString() is now 0.630kB. Final heap wa reduced from 897kB to a mere 254kB, a 72% reduction in the heap size. The execution time was 2.58 seconds, that's nearly 50% faster. That change took me about 3 minutes to make (once i created an NUnit test to verify that the existing code was right before i ripped it apart ;) ).

The lesson for today, when creating strings, use the StringBuilder class. It helps performance hugely.

Monday, December 18, 2006

There's been some interesting events in the P2P world recently.

On the 8th of December it was announced that uTorrent (probably the best bittorrent client around for windows, although closed source) had been bought by BitTorrent Inc. As a direct result of uTorrent being bought over and in the hands of the "enemy" (RIAA, MPAA etc), a lot of trackers are banning the use of uTorrent. This means that if you want to download anything off that tracker, you now cannot use uTorrent. One of the highly recommend options is Azureus, which as good as it may be, is also extremely bloated. Whereas uTorrent can download away with as little as 2 megs of ram, Azureus demands a minimum of 50 megs these days.

Personally, i think that this is a bit over the top. Banning the best client i've ever used simply because it has a new owner, BitTorrent inc, is a bit over the top. It's always possible that this decision will be changed in the future, but the odds are slim. Farewell to the best client ever.

Tuesday, December 12, 2006

One down, 5 to go.

My hardest (or maybe second hardest :p ) exam is now over. Think of differential equations more complex than anything you've seen before (unless you studied pure maths in college). Those are the kind of things i battled with earlier today. The questions were (unfortunately) the kind of ones that actually require you to think before even attempting an answer. It's not so simple as looking at a question and instantly knowing the way to solve it. It didn't help that the course is new and we had no past papers to look at for guidance. Anyway, it's over now!

I have another one tomorrow, tis maths aswell, but thankfully it's only vector calculus. Calculus and vectors. Vectors and calculus. It's a nice combination really. I never found either topic particularly difficult, so when combined they're not too bad!

I have 4 exams after maths: one on friday, one on saturday, one on monday and the last one on tuesday. The only tough one out of the lot is the monday exam, so that's gonna need a fair bit of work. Still, it'll all be over in 7 days. I can't wait for the christmas break.

Monday, December 04, 2006

So my exams are starting in less than 10 days. I'm slowly turning into an eat-sleep-study zombie. The pressure is on to cram as much as possible into my brain within the next week or two so i can do amazingly well... or at least thats what i tell myself. On one hand, the exams are only worth 15% of my final degree, so i don't have to perform amazingly well in these to walk out with a good degree next year, but any marks i pick up now remove some of the pressure from next year. It'd be nice going into final year knowing that i've already picked up 20+% of my final degree!

It's right about now that I begin to regret skipping all those lectures despite promising myself i wouldn't do that this year. I also wish i had finished off all those problem sheets a few weeks ago, but that never happened ;) Ah well, sure what's the worst that can happen! I have 9 days, i have coffee, what more do i need... except for more time ;)

On the plus side i've begun sticking monotorrent through an extensive regime of testing. I've transferred several gigs with it over the last few days/weeks and fixed a lot of little (and not so little) bugs. But the big test is when hundreds of people start using it and submitting bug reports. That'll be a great day ;) I just have to wait til after those blasted exams.

Hit Counter