Register forum user name Search FAQ

Gammon Forum

Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to verify your details, confirm your email, resolve issues, making threats, or asking for money, are spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the password reset link.

Due to spam on this forum, all posts now need moderator approval.

 Entire forum ➜ SMAUG ➜ Running the server ➜ Smaug FUSS stress test attempt

Smaug FUSS stress test attempt

It is now over 60 days since the last post. This thread is closed.     Refresh page


Posted by Nick Gammon   Australia  (23,140 posts)  Bio   Forum Administrator
Date Sun 15 Jun 2008 12:26 AM (UTC)

Amended on Sun 15 Jun 2008 12:27 AM (UTC) by Nick Gammon

Message
For a bit of fun I wrote an application in Lua (using LuaSocket) that was designed to stress-test the Smaug FUSS server (I was using Smaug FUSS 1.9).

I was curious to see how it would react if you pumped a few hundred players through it. Specifically, would it:


  • Crash?
  • Exhibit extreme lag?
  • Do other strange things?
  • Would certain combinations of class/race not work correctly?


The Lua code was designed to create a new level 1 player from scratch, using a random name, random gender, random class and random race.

It would then move about - yes you guessed it - randomly. ;)

Interestingly the server passed the test pretty well. It was also quite good fun to watch the MUD jump into life with players running everywhere. Here is an example of running it with 500 players (plus a couple I used to monitor what was happening):



Comm: Broke all-time maximum player record: 502
Monitor: Broke all-time maximum player record: 502


<10040hp 10000m 110mv> <#21000> 
who
  1 Paladin     Glerawyth the Keeper.
  2 Thief       Eowore the Footpad.
  2 Warrior     Agriand the Recruit.
  2 Thief       Oliedus the Footpad.
  2 Druid       Ibalena the Attendant.
  2 Cleric      Haolin the Attendant.
  2 Druid       Wylath the Attendant.
  1 Cleric      Kederracred the Believer.
  2 Warrior     Jeraenoic the Recruit.
  2 Druid       Griech the Attendant.
  2 Thief       Adweall the Footpad.
  2 Cleric      Nydilia the Attendant.

... and so on ...

  1 Warrior     Cowin the Swordpupil.
  1 Mage        Acelilla the Apprentice of Magic.
  1 Augurer     Ceawin the Docent of Wizardry.
  2 Vampire     Lotherra the Blood Student.
  1 Thief       Elardolath the Pilferer.
  1 Paladin     Vaeryan the Keeper.
  1 Vampire     Lothaledric the Apprentice of Blood.
  1 Ranger      Maymond the Runner.
  1 Cleric      Cadumond the Believer.
  1 Warrior     Olieth the Swordpupil.
  1 Cleric      Larelath the Believer.
  2 Druid       Aloalla the Attendant.
  1 Cleric      Glerana the Believer.
  1 Ranger      Wicuryan the Runner.
  1 Vampire     Larellyra the Apprentice of Blood.
  1 Mage        Daessa the Apprentice of Magic.
  1 Warrior     Raseth the Swordpupil.
  1 Mage        Croiwin the Apprentice of Magic.
  1 Mage        Dwoilgrin the Apprentice of Magic.

-----------------------------------[ IMMORTALS ]------------------------------

Supreme Entity  Admin the Attendant.
502 players.


I had the bots output a random social every 20 or 30 seconds, which with 500 players made things a bit noisy. They also drank if there was a fountain there, and yelled out if they levelled:


Edeibrylla sneers in contempt.
Rorel looks innocently about itself.
Etallyra meows like a kitten.
Eowoeloth desperately seeks someone to marry.
Gwaoch begins to squeak like a mouse.  Straaange.
Aoera whips out his flaming torches and begins to juggle them. Wow. What skill, what grace!
Mareder searches for a victim to tease.
Weraa leaves north.
Morenydd drinks from the fountain.
Ethalla drinks from the fountain.
Wicaectred flies in from above.
Laevudd drinks from the fountain.
Niraryan arrives from above.
Onaledon has entered the game.
Boilonna has begun to sing.
Delitlan wiggles his nose.
Eleriwyr stands and says, 'Hi, I'm Eleriwyr, and I'm a mud addict.'
Hungrily, a hollow voice asks 'What soul passes the gateway into this dominion?'
Ceaniver Looks happy! Awww whatta chum!
Gwoann looks particularly glum today.  *sniff*
Merimar hits her head on a tree and cries, "Not AGAIN!?"
Halit yells 'Woooooot!  Levelled!!!! (12/35 hp, 4/107 mana, 10/110 mv 3/3 prac.)'
Mendaldan looks around the room and asks everyone, "How are you?"
Cirach snaps his fingers.
Gweilla growls.
Cadash waves happily.
Daewin tightens his grip on his weapon, preparing for battle.
Wicaectred flies up.


Darkhaven Academy was a particularly busy place:


Darkhaven Academy                                          -     N     -
-<---- Vnum:  10300 ----------------------------->-        -<-U-(*)--->-
                                                           -     S     -

You stand inside the Darkhaven Academy, an establishment designed to teach
the basics of play inside this game.  Each room has a specific purpose and
contains information on the various commands to maneuver around and interact 
with the players.  We recommend you explore the Academy in full, taking the 
time to read the instructions in each room.
 
Type N to move north to the next room in the Academy.  If you have already
completed the rigors of the Academy and wish to test your combat mettle in
the battlegrounds, type OPEN S or OPEN DOOR, then S to enter the arena.
Exits: north up.
A large marble fountain gushes forth here.
Oliedus the Footpad is standing here.
Wylath the Attendant is standing here.
Eowore the Footpad is standing here.
Kederracred the Believer is standing here.
Roavyan the Attendant is standing here.

... and so on for about 5 pages ...

Pieth the Believer is hovering here.
Ceabwyn the Runner is hovering here.
Kedardog the Believer is standing here.
Pulla the Docent of Wizardry is standing here.
Delicred the Footpad is standing here.
Nardowyth the Pilferer is standing here.
Gwerraryan the Apprentice of Blood is standing here.
Gwealath the Docent of Wizardry is standing here.
Keina the Keeper is standing here.
Jaevyan the Attendant is standing here.
Thynd the Pilferer is hovering here.
Hawtlan the Apprentice of Magic is hovering here.
The illustrious Darkhaven Academy Headmistress stands here to greet you.
Mistress Tsythia is shrouded in flowing shadow and light.
Gwiratram flies in from above.
Gwiratram flies up.


However even with 502 players, the CPU load was fairly light:


  PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME CPU COMMAND
31368 nick      16   0 23236  22M  2380 R    13.0  3.6   3:10   0 smaug


That was around 13% CPU usage.

Response time on my client was slightly sluggish compared to normal, however that would partly be accounted for by the rather extreme quantities of network traffic. I wouldn't call it "lag" but it took a bit longer than usual to get a response.

I only had a single crash during the testing, and analyzing the crash with gdb seemed to indicate a corrupted stack, so one of the bots must have done something to cause that. Overall it was pretty stable, considering.

Conclusion

Smaug FUSS 1.9 seems to cope pretty well with 500+ players, with only slight lag, and an occasional crash.

Possible things you might change if you regularly had that many players would be to make some of the displays show summaries rather than listing every player. For example, instead of listing 300 players in one room you might say:


In the room with you are Oliedus, Wylath, Eowore, Kederracred, Roavyan and 297 other players.


It was hard to test fighting, making bots react correctly to lots of MUD input is harder than it seems. Some of the bots got into fights, which they often lost. To make fights work better you would need to make each class use its optimal attack, take into account whether it was winning or losing, be prepared to run away, heal itself, and so on. Automating all that is not particularly easy.

You also need to make the bots intelligently buy goods (eg. food), put it into bags, consume it when necessary, and so on. All in all, quite a challenge in writing an AI agent. :)


- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Robert Powell   Australia  (367 posts)  Bio
Date Reply #1 on Sun 15 Jun 2008 01:54 AM (UTC)
Message
Nick that is awesome, 500+ players would be somewhat extreme for a mud to have and its nice to know that the server can handle it.

At present i have 100 bots running on my localhost, i took a somewhat different approach to what you have done and have made individual scripts with a path that each bot follows, issuing commands along the way.

It was somewhat time consuming to create many script paths that can be somewhat complex with upto 100 commands in each list.

I would love to see the code for your test script, if your willing to share that is, i know you have reservations about posting it as it could be abused. perhaps you could emails it :))

Thanks again,

Just a guy having a bit of fun. Nothing more, nothing less, I do not need I WIN to feel validated.
Top

Posted by Llarn   (23 posts)  Bio
Date Reply #2 on Sun 15 Jun 2008 11:18 AM (UTC)
Message
Wow, sounds very impressive AI is always something of interest, as new players now adays tend to want to log on your game type who, and if no players there, quit before giving it a chance.
Top

Posted by Robert Powell   Australia  (367 posts)  Bio
Date Reply #3 on Sun 15 Jun 2008 12:01 PM (UTC)
Message
Quote:

Wow, sounds very impressive AI is always something of interest, as new players now adays tend to want to log on your game type who, and if no players there, quit before giving it a chance.


I don't think this sort of thing should be used as a make my mud look like its got players online sort of thing. Real players are pretty smart and can see through such simple trickery and would not play for long at such muds.

I have seen these sorts of tricks used on many muds, from padding out the who list with mobs, to showing dead linked players on the who list. All in all, if you need to fake how many players you have then there might be some more inherent design problems with the mud.

That said, i feel that there are some situations where the addition of a few bots to a game can possibly enhance the game experience as long as it is obvious to all that its a bot.

Having henchmen for hire (aka guild wars) to help you level is one such situation where a few bots can make the game much more fun. Another situation would be pure PK games, where a few player bots would give players during quiet times someone to go after and kill. This is something that i have been working on for my own game. Where the character would be called something obvious like BOT-Jonny so that all would know it is an AI character, but the kill would go towards PK stats rather than be just another mob kill.

QUESTION FOR NICK.

Does the script receive information back from the server that we can do regex things on to determine what to do next or is the script just dumb and holding a one way connection to the server.

Just a guy having a bit of fun. Nothing more, nothing less, I do not need I WIN to feel validated.
Top

Posted by Nick Gammon   Australia  (23,140 posts)  Bio   Forum Administrator
Date Reply #4 on Sun 15 Jun 2008 10:52 PM (UTC)

Amended on Sun 15 Jun 2008 10:53 PM (UTC) by Nick Gammon

Message
The script has a series of regexps that it tries to use to work out what is going on.

For example, you can send a tell to a bot and get a response:


<10040hp 10000m 110mv> <#21000> 
tell Araecan hi there
You tell Araecan 'hi there'

<10040hp 10000m 110mv> <#21000> 
Araecan tells you 'look Admin, I am just a poor wee Thief, I know nothing about that'

<10040hp 10000m 110mv> <#21000> 
Hungrily, a hollow voice asks 'What soul passes the gateway into this dominion?'
A rasping voice answers 'A neophyte Vampire known as Sialith ...'

<10040hp 10000m 110mv> <#21000> 
Sialith shouts 'Woooooot!  Levelled!!!! (15/42 hp, 1/12 bp, 10/110 mv 2/2 prac.)'

<10040hp 10000m 110mv> <#21000> 
Hungrily, a hollow voice asks 'What soul passes the gateway into this dominion?'
A rasping voice answers 'The acolyte Mage, Groand ...'


Notice in the reply he echoed back my name, and knew his class.

Also notice the players detect the "level up" message and do a shout when they get it.

I had a surprising amount of trouble making the bots react reasonably in a fight situation. The problem is that there are so many things that can go wrong. (eg. you are stunned, killed, the mob runs away, you flee, your health is low, etc.). Also in a busy MUD you might trigger "mob X is here" and try to fight it, and not notice that someone else started first.

In fact it is hard to auto-detect who to fight in the first place. I was trying to match on "The * here *" but consider this:


The illustrious Darkhaven Academy Headmistress stands here to greet you.


Then you type "kill illustrious" and get slaughtered.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Robert Powell   Australia  (367 posts)  Bio
Date Reply #5 on Sun 15 Jun 2008 11:53 PM (UTC)
Message
Quote:

Then you type "kill illustrious" and get slaughtered.


LOL well the design of my game makes my task a little easier as I don't have to contend with mobs like that, leveling mobs in my game are all on the overland map, and in the cities there is nothing that you can attack anyways.

Can you show me how to regex with lua.socket as i cannot get it to work. I have tryed playing with socket.receive but i think i am doing things very wrong.

Just a guy having a bit of fun. Nothing more, nothing less, I do not need I WIN to feel validated.
Top

Posted by Nick Gammon   Australia  (23,140 posts)  Bio   Forum Administrator
Date Reply #6 on Mon 16 Jun 2008 01:47 AM (UTC)

Amended on Mon 16 Jun 2008 01:48 AM (UTC) by Nick Gammon

Message
This stuff is fiddly to get right, and I don't really want to release the code as I can just imagine a wave of bots hitting various MUD servers. I am not saying you would do that Robert, but once out, such code has a habit of being shown to "a friend of a friend", and then eventually lands into the lap of someone who has a grudge against a MUD.

However I don't mind discussing general network programming concepts.

First thing you need to do is connect, eg.


local host = "10.0.0.50"  -- for example
local port = 4000
conn = assert (socket.connect (host, port))


This "conn" (connection) object is the thing you send or receive with. You make one per connection that you want to have.

You can send to the MUD with this, but the problem is that the network is not guaranteed to send everything. A simple example is:


conn:send ("west")


That will probably succeed, unless you batch up a lot of them.

You are better off finding out how much got sent, and keeping a running buffer, which you gradually send from.

eg.


count, err, count2 = conn:send (outbuf)
-- timeout just means we are trying to send too much
if err == "timeout" then
   err = nil
   count = count2
end -- timeout
  
-- write error? close connection
if err then
  print ("Error in send")
  conn:close () -- close it
else  -- not error
  outbuf = outbuf:sub (count + 1)  -- less to send next time
end -- if


What that does is send as much as it can, leaving the rest in outbuf.

Now what you do to send a new thing is simply append to outbuf, ready to be sent next time.

eg.


function send_to_mud (s)
  outbuf = outbuf .. s
end -- send_to_mud


Now to send and receive stuff you need a "select" loop. What select does is pause until there is something to do.

The general structure is like this:


while true do
  can_receive = {}
  can_send = {}

  -- do the steps below for each connection
  
  if outbuf ~= "" then
    table.insert (can_send, conn)
  end -- need to write
  
  -- check if we can read
  table.insert (can_receive, conn)
  
  
  -- wait for input or ability to send (1-second timeout)
  readable, writable  = socket.select (can_receive, can_send, 1)

  err = nil  -- no error yet
  s = nil  -- no input yet

   -- if we can receive, do so
   
  if readable [conn] then
    s, err, partial = conn:receive ("*l")
   -- timeout just means we are trying to receive too much
    if not s and err == "timeout" then
       err = nil
       s = partial
    end -- timeout
    
    -- read error? close connection
    if err then
      print ("Error in read")
      conn:close () -- close it
    else  -- not error
      if s then   -- have string? add to buffer
        inbuf = inbuf .. s .. "\n"  -- more input now
      end
    end -- got something
  end -- if we can receive
  
  -- if we can send, do so
  
  if not err and writable [conn] then
   
   -- do the send stuff I showed earlier on
   
  end -- if can send
  

  -- if still there, process it
  if not err then
   
    -- process input (inbuf) here 
          
  end -- no error on client send

end -- main loop


Effectively what we do is build a table of connections we want to read from (all of them) and connections we want to write to (those we have data for).

Then we call select. That will pause until we have input, or we are allowed to send something. This stops the program hogging all the CPU.

The call to select returns a table of the connections that actually can receive something, or be sent something. So we go through that table (I haven't shown that part) and for each item, we try to receive from it, or send to it.

Eventually you end up with inbuf being one or more lines of incoming text. You would break that into lines and then apply your regular expression to each one.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


30,352 views.

It is now over 60 days since the last post. This thread is closed.     Refresh page

Go to topic:           Search the forum


[Go to top] top

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.