Load Testing
Server Side
Legacy Tests - https://github.com/edx/load-tests (internal-only repo)
Current Tests - https://github.com/edx/edx-load-tests
Framework - https://github.com/locustio/locust(used currently in edx-load-tests. We also have a fork, and some legacy JMeter scripts)
Client Side (Browser)
Framework - http://www.sitespeed.io/ (Install via npm)
Useful add-in - https://github.com/edx/edx-sitespeed (for logged-in sessions)
Network throttling tools: Network Link Conditioner, tc (ubuntu native), wondersharper (which does not work on virtual machines), etc
Monitoring in Environments
New Relic
https://rpm.newrelic.com/accounts/88178/browser/1588430
Profiling
PyInstrument
PyInstrument can be helpful because of the way it writes output data as a call tree. More info here:
https://github.com/joerick/pyinstrument
Example of a profile using pyinstrument, writing output to a file:
from pyinstrument import Profiler profiler = Profiler(use_signal=False) profiler.start() # Do stuff here profiler.stop() # write profile data to file with open('my.log', 'w') as f: f.write(profiler.output_text())
SnakeViz
Here are the steps to profile your python code with cProfile and then view the results using SnakeViz.
- export VAGRANT_X11=1
- vagrant ssh
- First time only: Install SnakeViz. Please update this document with the steps you used if you do it.
- sudo su edxapp
Add the following to the code that you want to profile
from openedx.core.djangoapps.performance.utils import collect_profile with collect_profile: <python_code_to_profile>
Then use SnakeViz by issuing:
snakeviz DIRECTORY/FILE_NAME.profile
Tips
When profiling locally, disable features that would affect performance numbers. For instance, the following can be set in the a local [lms/cms]/envs/private.py file:
from .common import INSTALLED_APPS, MIDDLEWARE_CLASSES, FEATURES def tuple_without(source_tuple, exclusion_list): """Return new tuple excluding any entries in the exclusion list. Needed because tuples are immutable. Order preserved.""" return tuple([i for i in source_tuple if i not in exclusion_list]) INSTALLED_APPS = tuple_without(INSTALLED_APPS, ['debug_toolbar', 'debug_toolbar_mongo']) MIDDLEWARE_CLASSES = tuple_without(MIDDLEWARE_CLASSES, [ 'django_comment_client.utils.QueryCountDebugMiddleware', 'debug_toolbar.middleware.DebugToolbarMiddleware', ]) DEBUG_TOOLBAR_MONGO_STACKTRACES = False import contracts contracts.disable_all()