Page 1 of 1

New CppInterface callback problem

Posted: 23 Apr 2011, 10:53
by chromkorken
Hi,

I'm trying to code a simple threaded(boost) ai with the new Cpp interface (using the sample CCppTestAI from the git master)
(I'm new to C++ normaly I code in C/C99)
My Problem is that I cant use the callback outside of the cpptestai::CCppTestAI::HandleEvent function.
I tried to use it out of a boost::thread, from an external class,function,inside the handleevent but with another function. Nothing works!


the following two calls are working fine in HandleEvent (from cpptestai::CCppTestAI)

Code: Select all

callback->GetGame()->SendTextMessage(msgText.c_str(), 0);
callback->GetGame()->SendTextMessage("TICK2", 0);
if the folowing function get called from HandleEvent the game does a hangup.

Code: Select all

void K01AIn::K01AIc::WriteChat(const char* msg)//I renamed cpptestai::CCppTestAI
{
	callback->GetGame()->SendTextMessage(msg, 0);
}
Hangup:

Code: Select all

[f=0000000] <SkirmishAI: K01 0.1 (team 1)>: HI IM 1
[f=0000000] <SkirmishAI: K01 0.1 (team 1)>: Hello Engine (from CppTestA), num my unitZ is 1, first friendly units def name is: corcom
[f=0000000] <SkirmishAI: K01 0.1 (team 1)>: TICK2
[f=0000000] <SkirmishAI: K01 0.1 (team 1)>: whoo
[f=0000001] Skirmish AI "Enemy" (ID:0, Short-Name:"K01", Version:"0.1") took over control of team 1
spring: malloc.c:4631: _int_malloc: Assertion `(unsigned long)(size) >= (unsigned long)(nb)' failed.
[f=0000004] Aborted (SIGABRT) in spring 0.82+.4.0
[f=0000004] Stacktrace:
[f=0000004] [Watchdog] Hang detection triggered for Spring 0.82+.4.0.
[f=0000004]   (in thread: audio)
[f=0000004]   (in thread: main)
[f=0000004] Stacktrace (audio):
[f=0000004]   No Stacktraces for non-MainThread.
[f=0000004] Stacktrace (main):
[f=0000004]   (Note: This stacktrace is not 100% accurate! It just gives an impression.)
zsh: killed     /usr/local/bin/spring //I did a SIGKILL, because spring din't response to a SIGTERM
the following boost thread produces a SIGSEGV (it does the same not threaded)

Code: Select all

void testthread()
{
	boost::posix_time::seconds workTime(1);
for(;;)
{
	springai::OOAICallback* caback;
	caback->GetGame()->SendTextMessage("TICK5", 0);
	K01AI->WriteChat("TICK6");//K01AI is the cpptestai::CCppTestAI* ai object created in AIExport.cpp
	boost::this_thread::sleep(workTime);

}
}

Code: Select all

[f=0000000] Connection attempt from UnnamedPlayer
[f=0000000]  -> Version: 0.82+.4.0
[f=0000000]  -> Connection established (given id 0)
[f=0000000] Player UnnamedPlayer finished loading and is now ingame
[f=0000000] GameID: 548fb24d84d10af1eeba4b9e1cdf4421
[f=0000000] UnnamedPlayer added point: Start 0
[f=0000000] <SkirmishAI: K01 0.1 (team 1)>: HI IM 1
[f=0000000] <SkirmishAI: K01 0.1 (team 1)>: Hello Engine (from CppTestA), num my unitZ is 1, first friendly units def name is: corcom
[f=0000000] <SkirmishAI: K01 0.1 (team 1)>: TICK2
[f=0000001] Skirmish AI "Enemy" (ID:0, Short-Name:"K01", Version:"0.1") took over control of team 1
[f=0000004] Segmentation fault (SIGSEGV) in spring 0.82+.4.0
[f=0000004] Stacktrace:
[f=0000004] This stack trace indicates a problem with a Skirmish AI library.
[f=0000007]   <0> /lib/libc.so.6(+0x34780) [0x7fd79f858780]
[f=0000007]   <1> /spring/spring/AI/Skirmish/K01/src/CppTestAI.cpp:102
[f=0000007]   <2> /usr/lib/libboost_thread.so.1.46.0(thread_proxy+0x6c) [0x7fd7a144832c]
[f=0000007]   <3> /usr/lib64/libGL.so.1(+0x9e853) [0x7fd7a2bfc853]
*** glibc detected *** /usr/local/bin/spring: realloc(): invalid next size: 0x000000000b0cfde0 ***
======= Backtrace: =========
/lib/libc.so.6(+0x7342a)[0x7fd79f89742a]
/lib/libc.so.6(+0x75ee7)[0x7fd79f899ee7]
/lib/libc.so.6(realloc+0xf9)[0x7fd79f89b479]
/usr/lib64/libGL.so.1(+0x9f74d)[0x7fd7a2bfd74d]
======= Memory map: ========
00400000-00d99000 r-xp 00000000 08:01 4061114                            /usr/local/bin/spring
00f98000-00f9e000 rw-p 00998000 08:01 4061114                            /usr/local/bin/spring
00f9e000-01fdc000 rw-p 00000000 00:00 0
02578000-0cc87000 rw-p 00000000 00:00 0                                  [heap]
40192000-40209000 rw-p 00000000 00:00 0
41c31000-41c33000 r-xs 00000000 08:01 15885642                           /tmp/glGiofLx (deleted)
7fd777d80000-7fd777f80000 rw-s bf3c9000 00:0c 6713                       /dev/nvidia0
7fd778000000-7fd77b50d000 rw-p 00000000 00:00 0
7fd77b50d000-7fd77c000000 ---p 00000000 00:00 0
7fd77c059000-7fd77fe0c000 rw-p 00000000 00:00 0
7fd77fe0c000-7fd77fe0d000 ---p 00000000 00:00 0
7fd77fe0d000-7fd78060d000 rw-p 00000000 00:00 0
7fd78060d000-7fd78060e000 ---p 00000000 00:00 0
7fd78060e000-7fd780e0e000 rw-p 00000000 00:00 0
7fd781659000-7fd7835db000 rw-p 00000000 00:00 0
7fd7836db000-7fd7836dc000 ---p 00000000 00:00 0
7fd7836dc000-7fd783edc000 rw-p 00000000 00:00 0
7fd783edc000-7fd7840dc000 rw-s 0c61d000 00:0c 6713                       /dev/nvidia0
7fd7840dc000-7fd7840dd000 ---p 00000000 00:00 0
7fd7840dd000-7fd7848dd000 rw-p 00000000 00:00 0
7fd7848dd000-7fd7848e8000 r-xp 00000000 08:01 11641153                   /lib/libnss_files-2.13.so
7fd7848e8000-7fd784ae7000 ---p 0000b000 08:01 11641153                   /lib/libnss_files-2.13.so
7fd784ae7000-7fd784ae8000 r--p 0000a000 08:01 11641153                   /lib/libnss_files-2.13.so
7fd784ae8000-7fd784ae9000 rw-p 0000b000 08:01 11641153                   /lib/libnss_files-2.13.so
7fd784ae9000-7fd784bd3000 r-xp 00000000 08:01 4178519                    /usr/lib/libasound.so.2.0.0
7fd784bd3000-7fd784dd2000 ---p 000ea000 08:01 4178519                    /usr/lib/libasound.so.2.0.0
7fd784dd2000-7fd784dda000 rw-p 000e9000 08:01 4178519                    /usr/lib/libasound.so.2.0.0
7fd784e0f000-7fd784e10000 ---p 00000000 00:00 0
7fd784e10000-7fd785610000 rw-p 00000000 00:00 0
7fd785610000-7fd785614000 r-xp 00000000 08:01 11640954                   /lib/libattr.so.1.1.0
7fd785614000-7fd785813000 ---p 00004000 08:01 11640954                   /lib/libattr.so.1.1.0
7fd785813000-7fd785814000 rw-p 00003000 08:01 11640954                   /lib/libattr.so.1.1.0
7fd785814000-7fd785827000 r-xp 00000000 08:01 11641134                   /lib/libresolv-2.13.so
7fd785827000-7fd785a27000 ---p 00013000 08:01 11641134                   /lib/libresolv-2.13.so
7fd785a27000-7fd785a28000 r--p 00013000 08:01 11641134                   /lib/libresolv-2.13.so
7fd785a28000-7fd785a29000 rw-p 00014000 08:01 11641134                   /lib/libresolv-2.13.so
7fd785a29000-7fd785a2b000 rw-p 00000000 00:00 0
7fd785a2b000-7fd785cde000 r-xp 00000000 08:01 4178541                    /usr/lib/libvorbisenc.so.2.0.8
7fd785cde000-7fd785edd000 ---p 002b3000 08:01 4178541                    /usr/lib/libvorbisenc.so.2.0.8
7fd785edd000-7fd785ef9000 rw-p 002b2000 08:01 4178541                    /usr/lib/libvorbisenc.so.2.0.8
7fd785ef9000-7fd785f43000 r-xp 00000000 08:01 4178537                    /usr/lib/libFLAC.so.8.2.0
7fd785f43000-7fd786143000 ---p 0004a000 08:01 4178537                    /usr/lib/libFLAC.so.8.2.0
7fd786143000-7fd786145000 rw-p 0004a000 08:01 4178537                    /usr/lib/libFLAC.so.8.2.0
7fd786145000-7fd78615a000 r-xp 00000000 08:01 11641028                   /lib/libnsl-2.13.so
7fd78615a000-7fd786359000 ---p 00015000 08:01 11641028                   /lib/libnsl-2.13.so
7fd786359000-7fd78635a000 r--p 00014000 08:01 11641028                   /lib/libnsl-2.13.so
7fd78635a000-7fd78635b000 rw-p 00015000 08:01 11641028                   /lib/libnsl-2.13.so
7fd78635b000-7fd78635d000 rw-p 00000000 00:00 0
7fd78635d000-7fd786361000 r-xp 00000000 08:01 11641034                   /lib/libcap.so.2.20
7fd786361000-7fd786560000 ---p 00004000 08:01 11641034                   /lib/libcap.so.2.20
7fd786560000-7fd786561000 rw-p 00003000 08:01 11641034                   /lib/libcap.so.2.20
7fd786561000-7fd7865a4000 r-xp 00000000 08:01 4185074                    /usr/lib/libdbus-1.so.3.5.3
7fd7865a4000-7fd7867a4000 ---p 00043000 08:01 4185074                    /usr/lib/libdbus-1.so.3.5.3
7fd7867a4000-7fd7867a5000 r--p 00043000 08:01 4185074                    /usr/lib/libdbus-1.so.3.5.3
7fd7867a5000-7fd7867a6000 rw-p 00044000 08:01 4185074                    /usr/lib/libdbus-1.so.3.5.3
7fd7867a6000-7fd7867ab000 r-xp 00000000 08:01 4180172                    /usr/lib/libasyncns.so.0.3.1
7fd7867ab000-7fd7869aa000 ---p 00005000 08:01 4180172                    /usr/lib/libasyncns.so.0.3.1
7fd7869aa000-7fd7869ab000 rw-p 00004000 08:01 4180172                    /usr/lib/libasyncns.so.0.3.1
7fd7869ab000-7fd786a0b000 r-xp 00000000 08:01 4180526                    /usr/lib/libsndfile.so.1.0.24
7fd786a0b000-7fd786c0b000 ---p 00060000 08:01 4180526                    /usr/lib/libsndfile.so.1.0.24
7fd786c0b000-7fd786c0e000 rw-p 00060000 08:01 4180526                    /usr/lib/libsndfile.so.1.0.24
7fd786c0e000-7fd786c12000 rw-p 00000000 00:00 0
7fd786c12000-7fd786c1a000 r-xp 00000000 08:01 4228497                    /usr/lib/libwrap.so.0.7.6
7fd786c1a000-7fd786e19000 ---p 00008000 08:01 4228497                    /usr/lib/libwrap.so.0.7.6
7fd786e19000-7fd786e1b000 rw-p 00007000 08:01 4228497                    /usr/lib/libwrap.so.0.7.6
7fd786e1b000-7fd786e1e000 r-xp 00000000 08:01 4178661                    /usr/lib/libxcb-atom.so.1.0.0
7fd786e1e000-7fd78701e000 ---p 00003000 08:01 4178661                    /usr/lib/libxcb-atom.so.1.0.0
7fd78701e000-7fd78701f000 rw-p 00003000 08:01 4178661                    /usr/lib/libxcb-atom.so.1.0.0
7fd78701f000-7fd787024000 r-xp 00000000 08:01 4179071                    /usr/lib/libXtst.so.6.1.0
7fd787024000-7fd787224000 ---p 00005000 08:01 4179071                    /usr/lib/libXtst.so.6.1.0
7fd787224000-7fd787225000 rw-p 00005000 08:01 4179071                    /usr/lib/libXtst.so.6.1.0
7fd787225000-7fd787226000 r-xp 00000000 08:01 4179619                    /usr/lib/libX11-xcb.so.1.0.0
7fd787226000-7fd787425000 ---p 00001000 08:01 4179619                    /usr/lib/libX11-xcb.so.1.0.0
7fd787425000-7fd787426000 rw-p 00000000 08:01 4179619                    /usr/lib/libX11-xcb.so.1.0.0[f=0000007] Aborted (SIGABRT) in spring 0.82+.4.0
[f=0000007] Stacktrace:
[f=0000007] [Watchdog] Hang detection triggered for Spring 0.82+.4.0.
[f=0000007]   (in thread: main)
[f=0000007] Stacktrace (main):
[f=0000007]   (Note: This stacktrace is not 100% accurate! It just gives an impression.)
zsh: killed     /usr/local/bin/spring
so every time I try to use callback out of the HandleEvent function the game crashes.
Can anyone please tell me how to use the callback correctly outside the HandleEvent (from a thread?) ?

Re: New CppInterface callback problem

Posted: 23 Apr 2011, 13:26
by Kloot
chromkorken wrote: if the folowing function get called from HandleEvent the game does a hangup.

Code: Select all

void K01AIn::K01AIc::WriteChat(const char* msg)//I renamed cpptestai::CCppTestAI
{
	callback->GetGame()->SendTextMessage(msg, 0);
}
Does CPPTestAI crash if you add this WriteChat function and call it from HandleEvent?
chromkorken wrote: the following boost thread produces a SIGSEGV (it does the same not threaded)

Code: Select all

void testthread()
{
	boost::posix_time::seconds workTime(1);
for(;;)
{
	springai::OOAICallback* caback;
	caback->GetGame()->SendTextMessage("TICK5", 0);
	K01AI->WriteChat("TICK6");//K01AI is the cpptestai::CCppTestAI* ai object created in AIExport.cpp
	boost::this_thread::sleep(workTime);

}
}
Of course it does, <caback> is never initialized in this snippet (so it points to a random memory location).

NOTE: 99% of all engine callouts are _not_ threadsafe, they must be called by the same thread that callins (HandleEvent) run in.

Re: New CppInterface callback problem

Posted: 23 Apr 2011, 13:56
by chromkorken
just forking the thread kills the game, after removing the boost::thread the WriteChat function works inside HandleEvent. But how can I use the callback outside the HandleEvent oder the CppTestAi class? That still crashes the game. Setting it to public and use it from another class does a SIGSEGV.

Re: New CppInterface callback problem

Posted: 23 Apr 2011, 16:18
by AF
proxies, fallbacks, caches, etc

You cant just move your whole AI into a thread and have some magic fix to let you use the callback, that would make no sense from an engineering point of view.

When dealing with multithreading in NTai, I acquired all the information I needed on a task, put it in an object, then passed the object to a newly created thread. No resource sharing involved. Then at a later time, check back maybe in following frames for a result and do things based on that results.

Since AI logic itself is lightweight for the most part, you can take the heavy parts and put them in threads. Eitherway, how is the engine supposed to respond to a query about a units health when its finished the sim frame and it's in the middle of rendering?

Re: New CppInterface callback problem

Posted: 24 Apr 2011, 09:19
by hoijui
yeah... you can only call the callback from within the engines thread, which means, from within HandleEvent(). This is the case for all (native) AI Interfaces.

Re: New CppInterface callback problem

Posted: 24 Apr 2011, 14:56
by chromkorken
thank you all for your answers, you helped me allot :)

Re: New CppInterface callback problem

Posted: 26 May 2011, 19:06
by slind
AF wrote:proxies, fallbacks, caches, etc

You cant just move your whole AI into a thread and have some magic fix to let you use the callback, that would make no sense from an engineering point of view.
You could if you used a level of indirection. Setup a queue and redirect all of the calls the AI thread makes to the callback to put its calls onto the queue. The queue then waits until the engine makes a HandleEvent(update) call where it will dump all of its callback calls into the engine.

You can then define blocking and non-blocking callback commands. In essence what you are doing is developing a multi-thread safe kernel similar to what is used in an OS. See AcceptEX as an example.

*Note: this is by no means a trivial solution.

Re: New CppInterface callback problem

Posted: 26 May 2011, 20:20
by AF
So the AI begins and in the first frame the engine has a commander and 2 conbots.


So your AI spawns a thread and starts a lengthy cost evaluation complete with predictions and best cases for what to build next.

So it devises its commands, and waits for the next event handler.

The engine rejects your commands.

Puzzled, your AI flails about having failed. Meanwhile the engine has swapped out the commander during the first 5-10 frames as part of a gameplay feature. That commander and 2 conbots no longer exist, you now have the super mega battlecruiser given to you as part of a gameplay mode.

In this case, all engine API calls are blocking. There are no threadsafe methods/calls to the engine.

Re: New CppInterface callback problem

Posted: 26 May 2011, 22:52
by slind
AF wrote: The engine rejects your commands.

Puzzled, your AI flails about having failed.
AI flailing is the fault of the AI. If your AI does not adequately handle unit created/finished events correctly then it is going to flail. A multithreaded AI requires that the AI be able to abort its evaluation mid computation, throw away portions that are unneeded and recompute from a higher node in the tree. Not a restriction that needs to be placed on the engine. (Provided the engine rejects commands that don't make sense anymore in a sane fashion (i.e. not segfaulting)).
AF wrote: In this case, all engine API calls are blocking. There are no threadsafe methods/calls to the engine.
The idea is that you continue to compute possibilities and discard possibilities (tree branches) that become no longer possible as the engine updates the AI. Worst case scenario you suffer a O(N) penalty, N being your branching factor, to discard non-existent branches and a constant penalty associated with your static evaluator.

To implement this your AI would have to maintain an 'undo' stack that would maintain a sane world state when the engine starts rejecting callbacks.
AF wrote: 5-10 frames
The EventHandler function in your AI gets called at least once a frame right? Or is it scaled based upon framerate?

Re: New CppInterface callback problem

Posted: 27 May 2011, 00:28
by AF
To be fair in practice, the AI takes very little overhead, save for the big components involving searches, such as pathfinding, or building placement algorithms, all of which have their own pathing solutions without requiring the whole AI be lifted out, and all the complexities it brings.

Re: New CppInterface callback problem

Posted: 27 May 2011, 00:43
by slind
AF wrote:To be fair in practice, the AI takes very little overhead, save for the big components involving searches, such as pathfinding, or building placement algorithms, all of which have their own pathing solutions without requiring the whole AI be lifted out, and all the complexities it brings.
Most definitely.

Re: New CppInterface callback problem

Posted: 27 May 2011, 07:13
by hoijui
yeah.. in general you should try to use very little threads in AIs.
Remember that the engine its self will use more and more multi-threading (at least we hope so). one game may exist of 32 AIs (in theory, each of a different type, so they may not share any threads), a machine can run multiple games at a time and there might be other software running on the PC. so imagine your AI uses 4 threads, and you have it running 32 times. of course that reasoning is meaningless if your primary focus is not on a practical/user oriented AI, but rather research or something.
if that is not the case.. well just imagine if each photoshop or eclipse plugin would use multiple threads.

(in theory, it could be ~250 AIs per game, maybe more in the future even, but i chose 32 to stay somewhat realistic)

Re: New CppInterface callback problem

Posted: 27 May 2011, 18:16
by jK
I don't see a problem in multithreaded AIs.
From what I hear it is more a problem that the AIs aren't multithreaded currently so they can cause lags in human vs. 7 bots battles etc.
Sure the current AIs wouldn't profit by multithreading a lot, but when an AI would use more genetic algos & artificial neural networks it could become useful to move them to threads.
And the conflicting with engine threads doesn't matter, first we would never use 100% of all cores nor would an AI use such much time to stall other threads.

But yeah, to decrease amount of threads in extreme situations. You should reduce the amount of threads by using a shared libs.
So with multiple AI opponents you should have:
N=32: 32 threads + ~5 shared threads
(anything <512threads should be fine AFAIK)

Re: New CppInterface callback problem

Posted: 27 May 2011, 19:42
by Tobi
Depends all completely on 1) what those threads are doing and 2) the initial stack size they have.

Even 4000 threads could be fine if they are just waiting for I/O / some kind of signal 99.999% of the time.

Even 4 threads on a dual core machine could seriously slow the game down if they are all used to perform heavy calculations 100% of the time.

(Note that with the pthreads default you need 4GB of address space just for the stack of 512 threads.)

Re: New CppInterface callback problem

Posted: 27 May 2011, 20:29
by jK
ah crap, totally forgot the insanely high stacksize of pthreads ...

Re: New CppInterface callback problem

Posted: 28 May 2011, 01:23
by AF
Atm the only AIs that have any threading are NTai and unreleased/in development AIs. (Imbaczeks AI might have it, Im not sure though )