mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-23 00:01:36 +00:00
Improve benchmarking
- The benchmark addon now manages setting up and tearing down the backend and traffic processes itself. - Use wrk instead of hey. I get more consistent results with this tool, and hey shows a strange tail-latency bump that seems artificial. - Make termination behaviour simpler. The bencmark revealed a bug where .done events were not called if the proxy was shut down by an addon.
This commit is contained in:
parent
5f74adc2df
commit
b663a224a3
@ -21,6 +21,7 @@ class Channel:
|
|||||||
Raises:
|
Raises:
|
||||||
exceptions.Kill: All connections should be closed immediately.
|
exceptions.Kill: All connections should be closed immediately.
|
||||||
"""
|
"""
|
||||||
|
if not self.should_exit.is_set():
|
||||||
m.reply = Reply(m)
|
m.reply = Reply(m)
|
||||||
asyncio.run_coroutine_threadsafe(
|
asyncio.run_coroutine_threadsafe(
|
||||||
self.master.addons.handle_lifecycle(mtype, m),
|
self.master.addons.handle_lifecycle(mtype, m),
|
||||||
@ -36,6 +37,7 @@ class Channel:
|
|||||||
Decorate a message with a dummy reply attribute, send it to the master,
|
Decorate a message with a dummy reply attribute, send it to the master,
|
||||||
then return immediately.
|
then return immediately.
|
||||||
"""
|
"""
|
||||||
|
if not self.should_exit.is_set():
|
||||||
m.reply = DummyReply()
|
m.reply = DummyReply()
|
||||||
asyncio.run_coroutine_threadsafe(
|
asyncio.run_coroutine_threadsafe(
|
||||||
self.master.addons.handle_lifecycle(mtype, m),
|
self.master.addons.handle_lifecycle(mtype, m),
|
||||||
|
@ -81,7 +81,6 @@ class Master:
|
|||||||
self.addons.trigger("running")
|
self.addons.trigger("running")
|
||||||
while True:
|
while True:
|
||||||
if self.should_exit.is_set():
|
if self.should_exit.is_set():
|
||||||
asyncio.get_event_loop().stop()
|
|
||||||
return
|
return
|
||||||
self.addons.trigger("tick")
|
self.addons.trigger("tick")
|
||||||
await asyncio.sleep(0.1)
|
await asyncio.sleep(0.1)
|
||||||
@ -94,13 +93,18 @@ class Master:
|
|||||||
loop.run_forever()
|
loop.run_forever()
|
||||||
finally:
|
finally:
|
||||||
self.shutdown()
|
self.shutdown()
|
||||||
|
pending = asyncio.Task.all_tasks()
|
||||||
|
loop.run_until_complete(asyncio.gather(*pending))
|
||||||
loop.close()
|
loop.close()
|
||||||
self.addons.trigger("done")
|
self.addons.trigger("done")
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
|
if not self.should_exit.is_set():
|
||||||
if self.server:
|
if self.server:
|
||||||
self.server.shutdown()
|
self.server.shutdown()
|
||||||
self.should_exit.set()
|
self.should_exit.set()
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
loop.stop()
|
||||||
|
|
||||||
def _change_reverse_host(self, f):
|
def _change_reverse_host(self, f):
|
||||||
"""
|
"""
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
This directory contains a set of tools for benchmarking and profiling mitmproxy.
|
This directory contains an addon for benchmarking and profiling mitmproxy. At
|
||||||
At the moment, this is simply to give developers a quick way to see the impact
|
the moment, this is simply to give developers a quick way to see the impact of
|
||||||
of their work. Eventually, this might grow into a performance dashboard with
|
their work. Eventually, this might grow into a performance dashboard with
|
||||||
historical data, so we can track performance over time.
|
historical data, so we can track performance over time.
|
||||||
|
|
||||||
|
|
||||||
@ -9,48 +9,18 @@ historical data, so we can track performance over time.
|
|||||||
|
|
||||||
Install the following tools:
|
Install the following tools:
|
||||||
|
|
||||||
go get -u github.com/rakyll/hey
|
https://github.com/wg/wrk
|
||||||
|
|
||||||
go get github.com/cortesi/devd/cmd/devd
|
go get github.com/cortesi/devd/cmd/devd
|
||||||
|
|
||||||
You may also want to install snakeviz to make viewing profiles easier:
|
You may also want to install snakeviz to make viewing profiles easier:
|
||||||
|
|
||||||
pip install snakeviz
|
pip install snakeviz
|
||||||
|
|
||||||
In one window, run the devd server:
|
Now run the benchmark by loading the addon. A typical invocation is as follows:
|
||||||
|
|
||||||
./backend
|
|
||||||
|
|
||||||
|
|
||||||
# Running tests
|
|
||||||
|
|
||||||
Each run consists of two files - a mitproxy invocation, and a traffic generator.
|
|
||||||
Make sure the backend is started, then run the proxy:
|
|
||||||
|
|
||||||
./simple.mitmproxy
|
|
||||||
|
|
||||||
Now run the traffic generator:
|
|
||||||
|
|
||||||
./simple.traffic
|
|
||||||
|
|
||||||
After the run is done, quit the proxy with ctrl-c.
|
|
||||||
|
|
||||||
|
|
||||||
# Reading results
|
|
||||||
|
|
||||||
Results are placed in the ./results directory. You should see two files - a
|
|
||||||
performance log from **hey**, and a profile. You can view the profile like so:
|
|
||||||
|
|
||||||
snakeviz ./results/simple.prof
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
mitmdump -p0 -q --set benchmark_save_path=/tmp/foo -s ./benchmark.py
|
||||||
|
|
||||||
|
This will start up the backend server, run the benchmark, save the results to
|
||||||
|
/tmp/foo.bench and /tmp/foo.prof, and exit.
|
||||||
|
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
devd -p 10001 .
|
|
51
test/bench/benchmark.py
Normal file
51
test/bench/benchmark.py
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import asyncio
|
||||||
|
import cProfile
|
||||||
|
from mitmproxy import ctx
|
||||||
|
|
||||||
|
|
||||||
|
class Benchmark:
|
||||||
|
"""
|
||||||
|
A simple profiler addon.
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
self.pr = cProfile.Profile()
|
||||||
|
self.started = False
|
||||||
|
|
||||||
|
async def procs(self):
|
||||||
|
ctx.log.error("starting benchmark")
|
||||||
|
backend = await asyncio.create_subprocess_exec("devd", "-q", "-p", "10001", ".")
|
||||||
|
traf = await asyncio.create_subprocess_exec(
|
||||||
|
"wrk",
|
||||||
|
"-c50",
|
||||||
|
"-d5s",
|
||||||
|
"http://localhost:%s/benchmark.py" % ctx.master.server.address[1],
|
||||||
|
stdout=asyncio.subprocess.PIPE
|
||||||
|
)
|
||||||
|
stdout, _ = await traf.communicate()
|
||||||
|
open(ctx.options.benchmark_save_path + ".bench", mode="wb").write(stdout)
|
||||||
|
ctx.log.error(stdout.decode("ascii"))
|
||||||
|
backend.kill()
|
||||||
|
ctx.master.shutdown()
|
||||||
|
|
||||||
|
def load(self, loader):
|
||||||
|
loader.add_option(
|
||||||
|
"benchmark_save_path",
|
||||||
|
str,
|
||||||
|
"/tmp/profile",
|
||||||
|
"Destination for the .prof and and .bench result files"
|
||||||
|
)
|
||||||
|
ctx.options.update(
|
||||||
|
mode="reverse:http://devd.io:10001",
|
||||||
|
)
|
||||||
|
self.pr.enable()
|
||||||
|
|
||||||
|
def running(self):
|
||||||
|
if not self.started:
|
||||||
|
self.started = True
|
||||||
|
asyncio.get_event_loop().create_task(self.procs())
|
||||||
|
|
||||||
|
def done(self):
|
||||||
|
self.pr.dump_stats(ctx.options.benchmark_save_path + ".prof")
|
||||||
|
|
||||||
|
|
||||||
|
addons = [Benchmark()]
|
@ -1,25 +0,0 @@
|
|||||||
import cProfile
|
|
||||||
from mitmproxy import ctx
|
|
||||||
|
|
||||||
|
|
||||||
class Profile:
|
|
||||||
"""
|
|
||||||
A simple profiler addon.
|
|
||||||
"""
|
|
||||||
def __init__(self):
|
|
||||||
self.pr = cProfile.Profile()
|
|
||||||
|
|
||||||
def load(self, loader):
|
|
||||||
loader.add_option(
|
|
||||||
"profile_path",
|
|
||||||
str,
|
|
||||||
"/tmp/profile",
|
|
||||||
"Destination for the run profile, saved at exit"
|
|
||||||
)
|
|
||||||
self.pr.enable()
|
|
||||||
|
|
||||||
def done(self):
|
|
||||||
self.pr.dump_stats(ctx.options.profile_path)
|
|
||||||
|
|
||||||
|
|
||||||
addons = [Profile()]
|
|
4
test/bench/run
Executable file
4
test/bench/run
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
mkdir -p results
|
||||||
|
mitmdump -p0 -q --set benchmark_save_path=./results/mitmdump -s ./benchmark.py
|
@ -1,5 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
mkdir -p results
|
|
||||||
mitmdump -p 10002 --mode reverse:http://devd.io:10001 \
|
|
||||||
-s ./profiler.py --set profile_path=./results/simple.prof
|
|
@ -1,3 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
hey -disable-keepalive http://localhost:10002/profiler.py | tee ./results/simple.perf
|
|
Loading…
Reference in New Issue
Block a user