-
-
Notifications
You must be signed in to change notification settings - Fork 187
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add perftest to devtools * Add example output from the perf script * Rename to avoid pytest collection * Fix git mv failing to remove the original file..
- Loading branch information
Showing
2 changed files
with
154 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# Tools for developers | ||
|
||
This directory contains some simple scripts that can be useful for developers. | ||
|
||
## dump_devinfo | ||
* Queries the device and returns a fixture that can be added to the test suite | ||
|
||
```shell | ||
Usage: dump_devinfo.py [OPTIONS] HOST | ||
|
||
Generate devinfo file for given device. | ||
|
||
Options: | ||
-d, --debug | ||
--help Show this message and exit. | ||
``` | ||
|
||
## parse_pcap | ||
|
||
* Requires dpkt (pip install dpkt) | ||
* Reads a pcap file and prints out the device communications | ||
|
||
```shell | ||
Usage: parse_pcap.py [OPTIONS] FILE | ||
|
||
Parse pcap file and pretty print the communications and some statistics. | ||
|
||
Options: | ||
--help Show this message and exit. | ||
``` | ||
|
||
## perftest | ||
|
||
* Runs several rounds of update cycles for the given list of addresses, and prints out statistics about the performance | ||
|
||
```shell | ||
Usage: perf_test.py [OPTIONS] [ADDRS]... | ||
|
||
Options: | ||
--rounds INTEGER | ||
--help Show this message and exit. | ||
``` | ||
|
||
```shell | ||
$ python perf_test.py 192.168.xx.x 192.168.xx.y 192.168.xx.z 192.168.xx.f | ||
Running 5 rounds on ('192.168.xx.x', '192.168.xx.y', '192.168.xx.z', '192.168.xx.f') | ||
=== Testing using gather on all devices === | ||
took | ||
count mean std min 25% 50% 75% max | ||
type | ||
concurrently 5.0 0.097161 0.045544 0.05260 0.055332 0.088811 0.143082 0.145981 | ||
sequential 5.0 0.150506 0.005798 0.14162 0.149065 0.150499 0.155579 0.155768 | ||
=== Testing per-device performance === | ||
took | ||
count mean std min 25% 50% 75% max | ||
id | ||
<id>-HS110(EU) 5.0 0.044917 0.014984 0.035836 0.037728 0.037950 0.041610 0.071458 | ||
<id>-KL130(EU) 5.0 0.067626 0.032027 0.046451 0.046797 0.048406 0.076136 0.120342 | ||
<id>-HS110(EU) 5.0 0.055700 0.016174 0.042086 0.045578 0.048905 0.059869 0.082064 | ||
<id>-KP303(UK) 5.0 0.010298 0.003765 0.007773 0.007968 0.008546 0.010439 0.016763 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
"""Script for testing update performance on devices.""" | ||
import asyncio | ||
import time | ||
|
||
import asyncclick as click | ||
import pandas as pd | ||
|
||
from kasa import Discover | ||
|
||
|
||
async def _update(dev, lock=None): | ||
if lock is not None: | ||
await lock.acquire() | ||
await asyncio.sleep(2) | ||
try: | ||
start_time = time.time() | ||
# print("%s >> Updating" % id(dev)) | ||
await dev.update() | ||
# print("%s >> done in %s" % (id(dev), time.time() - start_time)) | ||
return {"id": f"{id(dev)}-{dev.model}", "took": (time.time() - start_time)} | ||
finally: | ||
if lock is not None: | ||
lock.release() | ||
|
||
|
||
async def _update_concurrently(devs): | ||
start_time = time.time() | ||
update_futures = [asyncio.ensure_future(_update(dev)) for dev in devs] | ||
await asyncio.gather(*update_futures) | ||
return {"type": "concurrently", "took": (time.time() - start_time)} | ||
|
||
|
||
async def _update_sequentially(devs): | ||
start_time = time.time() | ||
|
||
for dev in devs: | ||
await _update(dev) | ||
|
||
return {"type": "sequential", "took": (time.time() - start_time)} | ||
|
||
|
||
@click.command() | ||
@click.argument("addrs", nargs=-1) | ||
@click.option("--rounds", default=5) | ||
async def main(addrs, rounds): | ||
"""Test update performance on given devices.""" | ||
print(f"Running {rounds} rounds on {addrs}") | ||
devs = [] | ||
|
||
for addr in addrs: | ||
try: | ||
dev = await Discover.discover_single(addr) | ||
devs.append(dev) | ||
except Exception as ex: | ||
print(f"unable to add {addr}: {ex}") | ||
|
||
data = [] | ||
test_gathered = True | ||
|
||
if test_gathered: | ||
print("=== Testing using gather on all devices ===") | ||
for i in range(rounds): | ||
data.append(await _update_concurrently(devs)) | ||
await asyncio.sleep(2) | ||
|
||
await asyncio.sleep(5) | ||
|
||
for i in range(rounds): | ||
data.append(await _update_sequentially(devs)) | ||
await asyncio.sleep(2) | ||
|
||
df = pd.DataFrame(data) | ||
print(df.groupby("type").describe()) | ||
|
||
print("=== Testing per-device performance ===") | ||
|
||
futs = [] | ||
data = [] | ||
locks = {dev: asyncio.Lock() for dev in devs} | ||
for i in range(rounds): | ||
for dev in devs: | ||
futs.append(asyncio.ensure_future(_update(dev, locks[dev]))) | ||
|
||
for fut in asyncio.as_completed(futs): | ||
res = await fut | ||
data.append(res) | ||
|
||
df = pd.DataFrame(data) | ||
print(df.groupby("id").describe()) | ||
|
||
|
||
if __name__ == "__main__": | ||
main(_anyio_backend="asyncio") |