C# AI Interface, and Proof of concept C# AI - Page 6

C# AI Interface, and Proof of concept C# AI

Here is where ideas can be collected for the skirmish AI in development

Moderators: hoijui, Moderators

Kloot
Spring Developer
Posts: 1867
Joined: 08 Oct 2006, 16:58

Post by Kloot »

obsolete
Last edited by Kloot on 09 Oct 2007, 19:41, edited 2 times in total.
Tronic
Posts: 75
Joined: 30 Nov 2006, 03:21

Post by Tronic »

Apparently a lot of people think that C++ is just C with classes and a with a different name for malloc.

I took the liberty of writing the benchmark, posted on page 4, in C++ instead of C/C++ as it was written originally. After all, if you are going to use a language, you will be writing code in the way used in that language, right?

The following code is tidyed a bit to match typical C++ coding standards instead of CamelCaseVariableNames, etc. The algorithm hasn't been modified, but the original dynamically allocated array of bool was replaced with std::vector. This also eliminates the need for separate initialization, as std::vector can already do that on construction.

Code: Select all

#include <ctime>
#include <iostream>
#include <vector>

int count_primes(unsigned int maxprime) {
    std::vector<bool> prime(maxprime, true);
    unsigned int count = 0;
    for (unsigned int i = 2; i < maxprime; ++i) {
        if (!prime[i]) continue;
        ++count;
        for (unsigned int j = i * 2; j < maxprime; j += i) prime[j] = false;
    }
    return count;
}

int main() {
    using std::cout;
    using std::endl;
    clock_t start = clock();
    cout << "number of primes: " << count_primes(10000000) << endl;
    clock_t finish = clock();
    double time = double(finish - start) / CLOCKS_PER_SEC;
    cout << "elapsed time: " << time << endl;
}
This code takes 0.38 seconds to run on my machine, where the original C/C++ code took 0.99 seconds. Both were compiled with GCC 4.1.1 using -O2. I cannot benchmark C#, but assuming that the ratio is similar to that of the original benchmark, I'd say that C++ is about twice as fast as C#, WHEN USED CORRECTLY.

You should also notice that there is no possibility for memory leaks when writing modern C++. In this tiny program I just eliminated one occurence of dynamic memory allocation visible to the user (that was missing its delete[], btw). RAII is an idiom that, unlike GC, can eliminate all kinds of resource leaks and make cleaning up (especially after throwing exceptions) totally automatic (no need for try-finally or using(){} blocks everywhere), while GC can only manage memory and is lazy at that too, leading to higher RAM usage. RAII is a central point of modern C++ design, but Java-derived GC'ed languages such as C# simply cannot support it.

A global garbage collector is simply not needed in C++. There are other systems that can do resource management better (standard library containers, reference counting, Boost containers). However, there still are garbage collectors for C++ for those who wish to use them. These are mainly recommended for "repairing" old leaky code, not for new programs, though.
Last edited by Tronic on 30 Nov 2006, 04:43, edited 1 time in total.
User avatar
hughperkins
AI Developer
Posts: 836
Joined: 17 Oct 2006, 04:14

Post by hughperkins »

With -O2, the C++ version is faster than C#:

Code: Select all

H:\dev\test\testperf>primecs
number of primes: 664579
elapsed time: 2.4375

H:\dev\test\testperf>primevectormingwo2
number of primes: 664579
elapsed time: 1.75
Edit: just to confirm ,this is the vector code , compiled with mingw with -O2. mingw version is: 3.4.2 (mingw-special)
Last edited by hughperkins on 30 Nov 2006, 15:06, edited 3 times in total.
Tronic
Posts: 75
Joined: 30 Nov 2006, 03:21

Post by Tronic »

EDIT: Apparently you did re-run with optimizations and edited your message... Nice, but which C++ version did you use now, the one with std::vector<bool>, or the other? As stated, the performance difference between the two was quite dramatic (2.5 times) on my system. My original message follows:

You should let the compiler optimize. Here the vector<bool> takes 2.48 s when compiled with -O0. If that doesn't help, consider using another compiler. GCC, while not generally regarded as the fastest (MSVC or ICC are often used instead when speed is crucial), can still generate fairly efficient code.

... and of course you should either reserve space or actually resize to your target size, when you know the size in advance, like in this case. Other containers (such as std::deque) are better when the sizes vary wildly or when collections need to be merged (std::list).

In the above program the first line of the function constructs the vector directly to the right size, so the performance is already optimal.

Another point to consider is that std::vector is specialized for <bool>, which means that it can pack them, effectively reducing the RAM usage to 1/8 of what it would be with bool[].
User avatar
hughperkins
AI Developer
Posts: 836
Joined: 17 Oct 2006, 04:14

Post by hughperkins »

Note that in practice, choice of algorithm generally has a significantly larger effect on framerate etc than choice of language.

Here's a tweaked version of primecs running in C#:

Code: Select all

H:\dev\test\testperf>primecs
number of primes: 664579
elapsed time: 1.3125
Tronic
Posts: 75
Joined: 30 Nov 2006, 03:21

Post by Tronic »

Sure, but if the code is easier to write and shorter in C++, you can optimize easier ;)

Granted, C++ is slow to compile (especially on GCC) and won't easily allow changing the code on fly (like many scripting languages do), thus it may not be the best option for scripting. What I fail to see is where C# really fits, as it is not nice to write in, not as fast as C++ and not really cross-platform. Obviously scripting languages (Python, LUA, EcmaScript, ..) fight in their own league and comparing them with the traditional non-string-oriented statically typed languages (C, Java family, C++) is very difficult.

C++ is a very difficult language to learn entirely. Java isn't, because Sun removed all the advanced bits, making the language more like a small subset of C++. Unfortunately, this also means that it is very limited. C# has almost the same stuff "under the hood", but Microsoft has poured in plenty of syntactic sugar, which is nice, but cannot work around the fundamental issues.

Fortunately, one doesn't need to learn C++ entirely to use it very effectively. One shouldn't buy those C++ books written by Java or C coders. Rather, for beginners I'd recommend reading Accelerated C++, which takes a radical approach, going directly into modern C++, instead of taking the "Java way".

I'm still waiting for your benchmark results using both C++ versions and -O2. Seeing the optimized C# source code would be interesting too. Did you give up on the Sieve of Eratosthenes altogether or just wrote it in a different way?

Interestingly enough, -O2 -march=i386 seems to be running slightly faster than -O2 -march=pentium4. I'm clocking 0.35 s for the former.
User avatar
hughperkins
AI Developer
Posts: 836
Joined: 17 Oct 2006, 04:14

Post by hughperkins »

Original C# code: 2.43
vector code, mingw /O2 : 1.75
Tweaked C# code: 1.312
vector code, msvc /O2: 1.187
Last edited by hughperkins on 30 Nov 2006, 15:05, edited 1 time in total.
User avatar
jcnossen
Former Engine Dev
Posts: 2440
Joined: 05 Jun 2005, 19:13

Post by jcnossen »

Do you actually want to discuss a C# AI interface or just ramble about C++ a lot? There are other forums for that .. :?
Tronic
Posts: 75
Joined: 30 Nov 2006, 03:21

Post by Tronic »

Nah, I just hate it when people post incorrect benchmarks. Another kinda disturbing thing is that people might start writing AIs that won't run on my system because of the language (if Mono is not supported, or if Mono development terminates, possibly because of the Microsoft deal).

But anyway, case closed for me.
User avatar
AF
AI Developer
Posts: 20687
Joined: 14 Sep 2004, 11:32

Post by AF »

Actually, since mono is a novel project, its covered by the Microsoft deal.
hollowsoul
Posts: 665
Joined: 06 Jun 2006, 19:49

Post by hollowsoul »

# Mono, OpenOffice and Samba

* Under the patent agreement, customers will receive coverage for Mono, Samba, and OpenOffice as well as .NET and Windows Server.
* All of these technologies will be improved upon during the 5 years of the agreement and there are some limits on the coverage that would be provided for future technologies added to these offerings.
* The collaboration framework we have put in place allows us to work on complex subjects such as this where intellectual property and innovation are important parts of the conversation.
* Novell customers can use these technologies, secure in the knowledge that Microsoft and Novell are working together to offer the best possible joint solution.
http://www.novell.com/linux/microsoft/openletter.html

Depends if u are a novell customer or not
User avatar
hughperkins
AI Developer
Posts: 836
Joined: 17 Oct 2006, 04:14

Post by hughperkins »

Mono is one implementation of the ECMA-334 and 335 standards which you can download from links at:

http://www.dina.dk/~sestoft/ecma/

The class libraries are described by TR-84 at:

http://www.ecma-international.org/publi ... TR-084.zip

You can download and unzip this file to see the class library classes which are covered.

Image

Examples of classes covered by TR84:
*Majority of System, eg System.Int32 , System.Type, System.Exception
*System.Threading, eg System.Threading.Thread
*System.Text, eg System.Text.Encoding, System.Text.UTF8Encoding
*System.Runtime.InteropServices, eg System.Runtime.InteropServices.DllImportAttribute
*System.Xml.XmlTextReader, System.Xml.XmlTextWriter
*System.IO, eg System.IO.StreamWriter

Notable classes that are absent:
*everything in System.Windows.Forms. In fact, System.Windows is missing
*everything in System.Drawing. This includes notably Bitmap, which is used for example by DevIL.Net, and pretty much anything to do with images.
*System.Xml.XmlDocument, System.Xml.XmlElement, System.Xml.XmlNode
*System.Runtime.Remoting

Mono is one implementation of ECMA-334 and ECMA-335. There is an alternative implementation at http://dotgnu.org/ . dotgnu appears dormant at this time, but that could change.
User avatar
hughperkins
AI Developer
Posts: 836
Joined: 17 Oct 2006, 04:14

Post by hughperkins »

This is interesting: was playing with rendering S3Os with and without vertexarrays and vertexbuffers. The test is to render 100 XTA8 armcom S3Os and measure the framerate. We're using C#.

Here are the results:

- Vertex3d: 10fps
- cast to float + Vertex3f: 12fps
- VertexArray + DrawArrays: 17fps
- VBO + DrawArrays: 17fps

It's apparent that the VBO is not significantly faster than the raw VertexArray. This can be explained by the dev machine's having an onboard graphics card, so VBO memory is probably system memory. This isnt important to the test.

What's interesting is to compare the Vertex3f writes with the VertexArray and VBO version.

The VertexArray and VBO will run natively from the graphics card, in theory. At any rate, they're certainly running outside of the C# VM.

The Vertex3fs should crawl because of the number of function calls required, and the associated inter-language bandwidth. To put that into perspective, each unit is 4000 vertices, so each frame is 400,000 function calls, and 12fps is 5 million function calls per second, across the C#/C language boundary.

Note that TAO does take steps to remove the default security checks associated with calling into unmanaged code.

Here are the specifications for the test:

- unit is ARMCOM.3do, from XTA8, exported as ARMCOM.S3O using Upspring 1.43
- unit contains 1452 triangles, which is 4356 vertices
- 100 units rendered per frame, with texturing off, and backface culling enabled
- machine is 1.4GHz, 512MB Ram, Intel Extreme onboard graphics
- VM is .Net 2.0
- OS is Windows

Here is the relevant rendering code:

Code: Select all

    void RenderUnitPartDirect(UnitPart unitpart)
    {
        Gl.glBegin(Gl.GL_TRIANGLES);
        foreach (Primitive primitive in unitpart.Primitives)
        {
            Triangle triangle = primitive as Triangle;
            Vertex(triangle.Vertices[0].Pos);
            Vertex(triangle.Vertices[1].Pos);
            Vertex(triangle.Vertices[2].Pos);
        }
        Gl.glEnd();
    }

    void RenderUnitPartvbo(UnitPart unitpart)
    {
        Gl.glEnableClientState(Gl.GL_VERTEX_ARRAY);
        GlCheckError();

        Gl.glBindBufferARB(Gl.GL_ARRAY_BUFFER_ARB, unitvbo);
        GlCheckError();

        Gl.glVertexPointer(3, Gl.GL_FLOAT, 0, IntPtr.Zero);
        GlCheckError();

        Gl.glDrawArrays(Gl.GL_TRIANGLES, 0, numunitvertices );
        Gl.glDisableClientState(Gl.GL_VERTEX_ARRAY);
    }

    void RenderUnitPartVa(UnitPart unitpart)
    {
        Gl.glEnableClientState(Gl.GL_VERTEX_ARRAY);
        GlCheckError();

        Gl.glVertexPointer(3, Gl.GL_FLOAT, 0, vertexarray);
        GlCheckError();

        Gl.glDrawArrays(Gl.GL_TRIANGLES, 0, numunitvertices );
        Gl.glDisableClientState(Gl.GL_VERTEX_ARRAY);
    }

    void RenderUnitPart(UnitPart unitpart)
    {
        switch (rendertype)
        {
            case RenderTypeEnum.Direct:
                RenderUnitPartDirect(unitpart);
                break;
            case RenderTypeEnum.Va:
                RenderUnitPartVa(unitpart);
                break;
            case RenderTypeEnum.Vbo:
                RenderUnitPartvbo(unitpart);
                break;
        }
    }

    enum RenderTypeEnum
    {
        Vbo,
        Va,
        Direct
    }
    RenderTypeEnum rendertype = RenderTypeEnum.Direct;
In the drawing loop:

Code: Select all

                for (int x = 0; x < 100; x++)
                {
                     RenderUnitPart(unit.unitpart);
                     Gl.glTranslated(10, 0, 0);
                }
We can switch between the rendering mode by changing rendertype.

Full sourcecode + binary zip available on demand (GPL).

You can get the C# s3o loader from http://manageddreams.com/csai/S3oLoader.cs (GPL)

Edit: note that there might be some concern that the vertex3d code is only rendering one segment of the unit. Note that the Upspring 1.43 exporter exported the ARMCOM as a single segment (s3opiece struct), so this is not an issue.
Kloot
Spring Developer
Posts: 1867
Joined: 08 Oct 2006, 16:58

Post by Kloot »

This can be explained by the dev machine's having an onboard graphics card, so VBO memory is probably system memory. This isnt important to the test.
How do you figure that? If the VBO's are in (relatively slow) system memory then there's the additional constant overhead of transferring them to the (also-slow) GPU so you gain very little wrt rendering time, especially if they are large. Thus I think comparing VBO performance to immediate-mode rendertime is a bit skewed in this case, considering the compiler probably also optimizes those glVertex calls since they're all going into the same unmanaged code section anyway.
User avatar
hughperkins
AI Developer
Posts: 836
Joined: 17 Oct 2006, 04:14

Post by hughperkins »

Kloot wrote:the compiler probably also optimizes those glVertex calls since they're all going into the same unmanaged code section anyway.
Note that this was compiled in debug mode -> no compile-time optimization.
Kloot
Spring Developer
Posts: 1867
Joined: 08 Oct 2006, 16:58

Post by Kloot »

Ah, I stand corrected.
blubbi
Posts: 5
Joined: 21 Oct 2006, 16:59

Post by blubbi »

newbie question: does the current csai work with the current spring version?
i tried it several times ... it always crashes. not even the logfile mentioned in the wiki is created
User avatar
hughperkins
AI Developer
Posts: 836
Joined: 17 Oct 2006, 04:14

Post by hughperkins »

CSAI1 needs to be repackaged using the new loader.
User avatar
hughperkins
AI Developer
Posts: 836
Joined: 17 Oct 2006, 04:14

Post by hughperkins »

Started looking at Java a little.

Did a quick benchmark. Java is a little slower but not monstrously slower.

First the results, then a description of the test, link to sourcecode:

Java:

Code: Select all

H:\bin\java\jogl-1_0_0-windows-i586\jogl-1_0_0-windows-i586\lib>java Test
after show
0 fps 44232 triangles per frame
8 fps 44232 triangles per frame
8 fps 44232 triangles per frame
10 fps 44232 triangles per frame
8 fps 44232 triangles per frame
8 fps 44232 triangles per frame
10 fps 44232 triangles per frame
9 fps 44232 triangles per frame
8 fps 44232 triangles per frame
10 fps 44232 triangles per frame
8 fps 44232 triangles per frame
12 fps 44232 triangles per frame
13 fps 44232 triangles per frame
13 fps 44232 triangles per frame
12 fps 44232 triangles per frame
16 fps 44232 triangles per frame
13 fps 44232 triangles per frame
19 fps 44232 triangles per frame
19 fps 44232 triangles per frame
14 fps 44232 triangles per frame
16 fps 44232 triangles per frame
14 fps 44232 triangles per frame
16 fps 44232 triangles per frame
12 fps 44232 triangles per frame
8 fps 44232 triangles per frame
8 fps 44232 triangles per frame
8 fps 44232 triangles per frame
9 fps 44232 triangles per frame
8 fps 44232 triangles per frame
10 fps 44232 triangles per frame
8 fps 44232 triangles per frame
8 fps 44232 triangles per frame
8 fps 44232 triangles per frame
8 fps 44232 triangles per frame
C#:

Code: Select all

H:\bin\java\jogl-1_0_0-windows-i586\jogl-1_0_0-windows-i586\lib>test
requested window width/height: 500 500
15 fps 44232 triangles per frame
14 fps 44232 triangles per frame
14 fps 44232 triangles per frame
14 fps 44232 triangles per frame
14 fps 44232 triangles per frame
15 fps 44232 triangles per frame
22 fps 44232 triangles per frame
29 fps 44232 triangles per frame
30 fps 44232 triangles per frame
31 fps 44232 triangles per frame
39 fps 44232 triangles per frame
31 fps 44232 triangles per frame
13 fps 44232 triangles per frame
11 fps 44232 triangles per frame
12 fps 44232 triangles per frame
11 fps 44232 triangles per frame
10 fps 44232 triangles per frame
12 fps 44232 triangles per frame
14 fps 44232 triangles per frame
14 fps 44232 triangles per frame
15 fps 44232 triangles per frame
13 fps 44232 triangles per frame
12 fps 44232 triangles per frame
14 fps 44232 triangles per frame
12 fps 44232 triangles per frame
11 fps 44232 triangles per frame
14 fps 44232 triangles per frame
26 fps 44232 triangles per frame
39 fps 44232 triangles per frame
29 fps 44232 triangles per frame
32 fps 44232 triangles per frame
38 fps 44232 triangles per frame
17 fps 44232 triangles per frame
12 fps 44232 triangles per frame
First, it's obvious that in both cases there are significant variations in framerate over time. Either there's something running on the test computer that is causing this, or something in the program or VM is causing this.

C# is running about 50% faster.

The test is to draw 20,000 quads onto the screen per frame. No texturing, or normals.

We do this because this is probably the most demanding thing for both C# and Java: crossing the inter-language boundary.

From Java sourcecode:

Code: Select all

            numtrisperframe = 0;
            double radiusstep = 0.01;
            for( double radius = 0.1; radius < 3; radius += radiusstep )
            {
                gl.glBegin( GL.GL_QUADS );
                double step = Math.PI * 2 / 100;
                for( double angle = 0; angle <= Math.PI * 2 * 0.75; angle+= step )
                {
                    double x = radius * Math.sin( angle );
                    double y = radius * Math.cos( angle );
                    gl.glVertex3d( x,y,0);
                    
                    x = ( radius + radiusstep ) * Math.sin( angle );
                    y = ( radius + radiusstep ) * Math.cos( angle );
                    gl.glVertex3d( x,y,0);
                    
                    x = ( radius + radiusstep ) * Math.sin( angle + step );
                    y = ( radius + radiusstep ) * Math.cos( angle + step );
                    gl.glVertex3d( x,y,0);
                    
                    x = radius * Math.sin( angle + step );
                    y = radius * Math.cos( angle + step );
                    gl.glVertex3d( x,y,0);
                    numtrisperframe += 2;
                }
                gl.glEnd();
            }
To make things visually interesting, we rotate the whole thing about the z and x axis over time.

Hardware environment:
- Intel Extreme onboard graphics
- 1.4GHz processor

Software environment:
- Windows
- Java 6
- .Net 2.0

Sourcecode:

http://manageddreams.com/csai/javavscs.zip

Edit: the variation in framerate over time is because we are rotating the disc about the x-axis, so sometimes the polygons are facing us and sometimes they are facing away.
blubbi
Posts: 5
Joined: 21 Oct 2006, 16:59

Post by blubbi »

hugh: do you mean the included .bat file? (that didnt work)
Post Reply

Return to “AI”