<p>Python’s <codeclass="docutils literal notranslate"><spanclass="pre">timeit</span></code> module is very good for testing small things. For example, in
order to test if it is faster to use a <codeclass="docutils literal notranslate"><spanclass="pre">for</span></code> loop or a list comprehension you
<spanclass="c1"># Time to do 1000000 for loops</span>
<spanclass="n">timeit</span><spanclass="o">.</span><spanclass="n">timeit</span><spanclass="p">(</span><spanclass="s2">"for i in range(100):</span><spanclass="se">\n</span><spanclass="s2"> a.append(i)"</span><spanclass="p">,</span><spanclass="n">setup</span><spanclass="o">=</span><spanclass="s2">"a = []"</span><spanclass="p">)</span>
<spanclass="c1"># Time to do 1000000 list comprehensions</span>
<spanclass="n">timeit</span><spanclass="o">.</span><spanclass="n">timeit</span><spanclass="p">(</span><spanclass="s2">"a = [i for i in range(100)]"</span><spanclass="p">)</span>
<p>The <codeclass="docutils literal notranslate"><spanclass="pre">setup</span></code> keyword is used to set up things that should not be included in the
time measurement, like <codeclass="docutils literal notranslate"><spanclass="pre">a</span><spanclass="pre">=</span><spanclass="pre">[]</span></code> in the first call.</p>
<p>By default the <codeclass="docutils literal notranslate"><spanclass="pre">timeit</span></code> function will re-run the given test 1000000 times and
returns the <em>total time</em> to do so (so <em>not</em> the average per test). A hint is to
not use this default for testing something that includes database writes - for
that you may want to use a lower number of repeats (say 100 or 1000) using the
<p>Python comes with its own profiler, named cProfile (this is for cPython, no
tests have been done with <codeclass="docutils literal notranslate"><spanclass="pre">pypy</span></code> at this point). Due to the way Evennia’s
processes are handled, there is no point in using the normal way to start the
profiler (<codeclass="docutils literal notranslate"><spanclass="pre">python</span><spanclass="pre">-m</span><spanclass="pre">cProfile</span><spanclass="pre">evennia.py</span></code>). Instead you start the profiler
<p>This will start Evennia with the Server component running (in daemon mode) under
cProfile. You could instead try <codeclass="docutils literal notranslate"><spanclass="pre">--profile</span></code> with the <codeclass="docutils literal notranslate"><spanclass="pre">portal</span></code> argument to
<p>Please note that while the profiler is running, your process will use a lot more
memory than usual. Memory usage is even likely to climb over time. So don’t
leave it running perpetually but monitor it carefully (for example using the
<codeclass="docutils literal notranslate"><spanclass="pre">top</span></code> command on Linux or the Task Manager’s memory display on Windows).</p>
<p>Once you have run the server for a while, you need to stop it so the profiler
can give its report. Do <em>not</em> kill the program from your task manager or by
sending it a kill signal - this will most likely also mess with the profiler.
Instead either use <codeclass="docutils literal notranslate"><spanclass="pre">evennia.py</span><spanclass="pre">stop</span></code> or (which may be even better), use
<codeclass="docutils literal notranslate"><spanclass="pre">@shutdown</span></code> from inside the game.</p>
<p>Once the server has fully shut down (this may be a lot slower than usual) you
will find that profiler has created a new file <codeclass="docutils literal notranslate"><spanclass="pre">mygame/server/logs/server.prof</span></code>.</p>
<h3>Analyzing the profile<aclass="headerlink"href="#analyzing-the-profile"title="Permalink to this headline">¶</a></h3>
<p>The <codeclass="docutils literal notranslate"><spanclass="pre">server.prof</span></code> file is a binary file. There are many ways to analyze and
display its contents, all of which has only been tested in Linux (If you are a
Windows/Mac user, let us know what works).</p>
<p>You can look at the contents of the profile file with Python’s in-built <codeclass="docutils literal notranslate"><spanclass="pre">pstats</span></code>
module in the evennia shell (it’s recommended you install <codeclass="docutils literal notranslate"><spanclass="pre">ipython</span></code> with <codeclass="docutils literal notranslate"><spanclass="pre">pip</span><spanclass="pre">install</span><spanclass="pre">ipython</span></code> in your virtualenv first, for prettier output):</p>
<p>You can also visualize the data in various ways.</p>
<ulclass="simple">
<li><p><aclass="reference external"href="https://pypi.org/project/RunSnakeRun/">Runsnake</a> visualizes the profile to
give a good overview. Install with <codeclass="docutils literal notranslate"><spanclass="pre">pip</span><spanclass="pre">install</span><spanclass="pre">runsnakerun</span></code>. Note that this
may require a C compiler and be quite slow to install.</p></li>
<li><p>For more detailed listing of usage time, you can use
<aclass="reference external"href="http://kcachegrind.sourceforge.net/html/Home.html">KCachegrind</a>. To make
KCachegrind work with Python profiles you also need the wrapper script
<aclass="reference external"href="https://pypi.python.org/pypi/pyprof2calltree/">pyprof2calltree</a>. You can get
<codeclass="docutils literal notranslate"><spanclass="pre">pyprof2calltree</span></code> via <codeclass="docutils literal notranslate"><spanclass="pre">pip</span></code> whereas KCacheGrind is something you need to get
via your package manager or their homepage.</p></li>
</ul>
<p>How to analyze and interpret profiling data is not a trivial issue and depends
on what you are profiling for. Evennia being an asynchronous server can also
confuse profiling. Ask on the mailing list if you need help and be ready to be
able to supply your <codeclass="docutils literal notranslate"><spanclass="pre">server.prof</span></code> file for comparison, along with the exact
<li><p>Stop your server completely with <codeclass="docutils literal notranslate"><spanclass="pre">evennia</span><spanclass="pre">stop</span></code>.</p></li>
<li><p>At <em>the end</em> of your <codeclass="docutils literal notranslate"><spanclass="pre">mygame/server/conf.settings.py</span></code> file, add the line</p>
<p>This will override your settings and disable Evennia’s rate limiters and
DoS-protections, which would otherwise block mass-connecting clients from
one IP. Notably, it will also change to a different (faster) password hasher.</p>
</li>
<li><p>(recommended): Build a new database. If you use default Sqlite3 and want to
keep your existing database, just rename <codeclass="docutils literal notranslate"><spanclass="pre">mygame/server/evennia.db3</span></code> to
<codeclass="docutils literal notranslate"><spanclass="pre">mygame/server/evennia.db3_backup</span></code> and run <codeclass="docutils literal notranslate"><spanclass="pre">evennia</span><spanclass="pre">migrate</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">evennia</span><spanclass="pre">start</span></code> to create a new superuser as usual.</p></li>
<li><p>(recommended) Log into the game as your superuser. This is just so you
can manually check response. If you kept an old database, you will <em>not</em>
be able to connect with an <em>existing</em> user since the password hasher changed!</p></li>
<li><p>Start the dummyrunner with 10 dummy users from the terminal with</p>
<p>The inputs/outputs from the dummy will then be printed. By default the runner
uses the ‘looker’ profile, which just logs in and sends the ‘look’ command
over and over. To change the settings, copy the file
<codeclass="docutils literal notranslate"><spanclass="pre">evennia/server/profiling/dummyrunner_settings.py</span></code> to your <codeclass="docutils literal notranslate"><spanclass="pre">mygame/server/conf/</span></code>
directory, then add this line to your settings file to use it in the new
<p>At the bottom of the default file are a few default profiles you can test out
by just setting the <codeclass="docutils literal notranslate"><spanclass="pre">PROFILE</span></code> variable to one of the options.</p>
<sectionid="dummyrunner-hints">
<h3>Dummyrunner hints<aclass="headerlink"href="#dummyrunner-hints"title="Permalink to this headline">¶</a></h3>
<ulclass="simple">
<li><p>Don’t start with too many dummies. The Dummyrunner taxes the server much more
than ‘real’ users tend to do. Start with 10-100 to begin with.</p></li>
<li><p>Stress-testing can be fun, but also consider what a ‘realistic’ number of
users would be for your game.</p></li>
<li><p>Note in the dummyrunner output how many commands/s are being sent to the
server by all dummies. This is usually a lot higher than what you’d
realistically expect to see from the same number of users.</p></li>
<li><p>The default settings sets up a ‘lag’ measure to measaure the round-about
message time. It updates with an average every 30 seconds. It can be worth to
have this running for a small number of dummies in one terminal before adding
more by starting another dummyrunner in another terminal - the first one will
act as a measure of how lag changes with different loads. Also verify the
lag-times by entering commands manually in-game.</p></li>
<li><p>Check the CPU usage of your server using <codeclass="docutils literal notranslate"><spanclass="pre">top/htop</span></code> (linux). In-game, use the
<li><p>You can run the server with <codeclass="docutils literal notranslate"><spanclass="pre">--profiler</span><spanclass="pre">start</span></code> to test it with dummies. Note
that the profiler will itself affect server performance, especially memory
consumption.</p></li>
<li><p>Generally, the dummyrunner system makes for a decent test of general
performance; but it is of course hard to actually mimic human user behavior.
For this, actual real-game testing is required.</p></li>