Skip to content

Commit

Permalink
update perf network detail data
Browse files Browse the repository at this point in the history
  • Loading branch information
huang1988519 committed Dec 18, 2022
1 parent 67b0e99 commit 29d6d16
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 27 deletions.
18 changes: 11 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -332,13 +332,17 @@ $ tidevice syslog

```bash
# 性能采集
$ tidevice perf -B com.example.demo
fps {'fps': 0, 'value': 0, 'timestamp': 1620725299495}
network {'timestamp': 1620725300511, 'downFlow': 55685.94921875, 'upFlow': 2300.96484375}
screenshot {'value': <PIL.PngImagePlugin.PngImageFile image mode=RGB size=231x500 at 0x1037CF760>, 'timestamp': 1620725301374}
fps {'fps': 58, 'value': 58, 'timestamp': 1620725873152}
cpu {'timestamp': 1620725873348, 'pid': 21243, 'value': 1.2141945711006428}
memory {'pid': 21243, 'timestamp': 1620725873348, 'value': 40.54920196533203}
$ tidevice perf -B com.example.demo --json

cpu {"timestamp": 1671173334888, "pid": 18717, "value": 0.0, "sys_value": 53.26736370425692, "count": 6}
memory {"pid": 18717, "timestamp": 1671173334888, "value": 10.20428466796875}
gpu {"device": 0, "renderer": 0, "tiler": 0, "value": 0, "timestamp": 1671173331745}
fps {"fps": 0, "value": 0, "timestamp": 1671173331745}
network {"connection-detected": {"Local": "[fe80::5cd8:6aff:fe80:78c3]:54658", "Remote": "[::]:0", "InterfaceIndex": 10, "Pid": -2, "RecvBufferSize": 131072, "RecvBufferUsed": 0, "SerialNumber": 14, "Protocol": "tcp6"}, "timestamp": 1671173331756}
network {"interface-detection": {"InterfaceIndex": 10, "Name": "anpi0"}, "timestamp": 1671173331767}
network {"interface-detection": {"InterfaceIndex": 14, "Name": "en0"}, "timestamp": 1671173331767}
network {"connection-update": {"RxPackets": 2, "RxBytes": 72, "TxPackets": 3, "TxBytes": 163, "RxDups": null, "RxOOO": null, "TxRetx": null, "MinRTT": 0.039375, "AvgRTT": 0.042, "ConnectionSerial": 56, "Time": 2}, "timestamp": 1671173335754}
...
```

```bash
Expand Down
21 changes: 15 additions & 6 deletions tidevice/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,6 @@ def cmd_ps(args: argparse.Namespace):


def cmd_perf(args: argparse.Namespace):
assert args.bundle_id
#print("BundleID:", args.bundle_id)
from ._perf import Performance
d = _udid2device(args.udid)
Expand All @@ -617,21 +616,28 @@ def cmd_perf(args: argparse.Namespace):
perfs = []
for _typename in args.perfs.split(","):
perfs.append(DataType(_typename))
# print(perfs)

if (DataType.MEMORY in perfs or DataType.CPU in perfs) and not args.bundle_id:
print('\033[1;31m error: the following arguments are required: -B/--bundle_id \033[0m')
exit(-1)

perf = Performance(d, perfs=perfs)

def _cb(_type: DataType, data):
print(_type.value, data, flush=True)
if args.json and _type != DataType.SCREENSHOT:
data = json.dumps(data)
print(_type.value, data, flush=True) if len(perfs) != 1 else print(data,flush=True)

try:
perf.start(args.bundle_id, callback=_cb)
#print("Ctrl-C to finish")
while True:
time.sleep(.1)
except KeyboardInterrupt:
pass
finally:
perf.stop()


def cmd_set_assistive_touch(args: argparse.Namespace):
d = _udid2device(args.udid)
d.set_assistive_touch(args.enabled)
Expand Down Expand Up @@ -895,12 +901,15 @@ def cmd_test(args: argparse.Namespace):
command="perf",
flags=[
dict(args=['-B', '--bundle_id'],
help='app bundle id',
required=True),
help='app bundle id (cpu/memory required)',
required=False),
dict(args=['-o'],
dest='perfs',
help='cpu,memory,fps,network,screenshot. separate by ","',
required=False),
dict(args=['--json'],
action='store_true',
help='format output as json'),
],
help="performance of app"),
dict(action=cmd_set_assistive_touch,
Expand Down
80 changes: 72 additions & 8 deletions tidevice/_instruments.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
from collections import defaultdict, namedtuple
from typing import Any, Iterator, List, Optional, Tuple, Union

from ctypes import Structure,c_byte,c_uint16,c_uint32
from socket import inet_ntoa,htons,inet_ntop,AF_INET6
from retry import retry

from . import bplist
Expand Down Expand Up @@ -55,6 +57,31 @@
['payload', 'header', 'message_id', 'channel_id', 'flags', 'result'])



class SockAddr4(Structure):
_fields_ = [
('len', c_byte),
('family', c_byte),
('port', c_uint16),
('addr', c_byte * 4),
('zero', c_byte * 8)
]

def __str__(self):
return f"{inet_ntoa(self.addr)}:{htons(self.port)}"

class SockAddr6(Structure):
_fields_ = [
('len', c_byte),
('family', c_byte),
('port', c_uint16),
('flowinfo', c_uint32),
('addr', c_byte * 16),
('scopeid', c_uint32)
]
def __str__(self):
return f"[{inet_ntop(AF_INET6, self.addr)}]:{htons(self.port)}"

class DTXPayload:
@staticmethod
def parse(payload: Union[bytes, bytearray]) -> typing.Tuple[int, Any]:
Expand Down Expand Up @@ -828,6 +855,10 @@ def iter_opengl_data(self) -> Iterator[dict]:
finally:
self.close()

def stop_iter_opengl_data(self):
channel = self.make_channel(InstrumentsService.GraphicsOpengl)
return self.call_message(channel,"stopSampling")

def iter_application_notification(self) -> Iterator[dict]:
""" 监听应用通知
Iterator data
Expand Down Expand Up @@ -940,6 +971,10 @@ def iter_cpu_memory(self) -> Iterator[dict]:
# aux.append_obj(channel_id)
# self.send_dtx_message(channel_id, DTXPayload.build('_channelCanceled:', aux))

def stop_iter_cpu_memory(self):
channel_id = self.make_channel(InstrumentsService.Sysmontap)
return self.call_message(channel_id,"stop")

def start_energy_sampling(self, pid: int):
ch_network = InstrumentsService.XcodeEnergyStatistics
return self.call_message(ch_network, 'startSamplingForPIDs:', [{pid}])
Expand Down Expand Up @@ -986,6 +1021,9 @@ def stop_network_sampling(self, pid: int):
ch_network = 'com.apple.xcode.debug-gauge-data-providers.NetworkStatistics'
return self.call_message(ch_network, 'stopSamplingForPIDs:', [{pid}])

def stop_network_iter(self):
return self.call_message(InstrumentsService.Networking, 'stopMonitoring:')

def get_process_network_stats(self, pid: int) -> Optional[dict]:
"""
经测试数据始终不是很准,用safari测试,每次刷新图片的时候,rx.bytes总是不动
Expand Down Expand Up @@ -1025,19 +1063,45 @@ def iter_network(self) -> Iterator[dict]:

noti_chan = (1<<32) - channel_id
it = self.iter_message(Event.NOTIFICATION)
self.call_message(channel_id, "replayLastRecordedSession")
self.call_message(channel_id, "startMonitoring")

headers = {
0: ['InterfaceIndex', "Name"],# 网关类型 en0:14 en2:12 anpi0:10
1: ['Local', 'Remote', 'InterfaceIndex', 'Pid', 'RecvBufferSize', 'RecvBufferUsed', 'SerialNumber', 'Protocol'],
# PacketsIn、ByteIn、PacketsOut、ByteOut、Dups Receieved、Out-Of-order、Retransmitted、Min Round Trip(ms)、Avg Round Trip(ms)
2: ['RxPackets', 'RxBytes', 'TxPackets', 'TxBytes', 'RxDups', 'RxOOO', 'TxRetx', 'MinRTT', 'AvgRTT', 'ConnectionSerial', 'Time']
}
msg_type = {
0: "interface-detection",
1: "connection-detected",
2: "connection-update",
}
for data in it:
if data.channel_id != noti_chan:
continue
(_type, values) = data.result
if _type == 2:
rx_packets, rx_bytes, tx_packets, tx_bytes = values[:4]
yield {
"rx.packets": rx_packets,
"rx.bytes": rx_bytes,
"tx.packets": tx_packets,
"tx.bytes": tx_bytes,
}

if _type == 1:
if len(values[0]) == 16:
values[0] = SockAddr4.from_buffer_copy(values[0])
values[1] = SockAddr4.from_buffer_copy(values[1])
values[-1] = 'tcp4' if values[-1] == 1 else 'udp4'
elif len(values[0]) == 28:
values[0] = SockAddr6.from_buffer_copy(values[0])
values[1] = SockAddr6.from_buffer_copy(values[1])
values[-1] = 'tcp6' if values[-1] == 1 else 'udp6'

for idx,v in enumerate(values):
if isinstance(v, int) or isinstance(v, float):
pass
elif isinstance(v, bplist.NSNull):
values[idx] = None
else:
values[idx] = str(v)
yield {
msg_type[_type]: dict(zip(headers[_type], values))
}

def is_running_pid(self, pid: int) -> bool:
aux = AUXMessageBuffer()
Expand Down
22 changes: 16 additions & 6 deletions tidevice/_perf.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,11 +254,13 @@ def iter_network_flow(d: BaseDevice, rp: RunningProcess) -> Iterator[Any]:
# if n < 2:
# n += 1
# continue
yield DataType.NETWORK, {
"timestamp": gen_stimestamp(),
"downFlow": (nstat['rx.bytes'] or 0) / 1024,
"upFlow": (nstat['tx.bytes'] or 0) / 1024
}
nstat['timestamp'] = gen_stimestamp()
yield DataType.NETWORK, nstat
# {
# "timestamp": gen_stimestamp(),
# "downFlow": (nstat['rx.bytes'] or 0) / 1024,
# "upFlow": (nstat['tx.bytes'] or 0) / 1024
# }


def append_data(wg: WaitGroup, stop_event: threading.Event,
Expand Down Expand Up @@ -326,7 +328,15 @@ def _thread_start(self, callback: CallbackType):

def stop(self): # -> PerfReport:
self._stop_event.set()
print("Stopped")
with self._d.connect_instruments() as ts:
print('Stop Sampling...')
if DataType.NETWORK in self._perfs: ts.stop_network_iter()
if DataType.GPU in self._perfs or DataType.FPS in self._perfs: ts.stop_iter_opengl_data()
if DataType.CPU in self._perfs or DataType.MEMORY in self._perfs: ts.stop_iter_cpu_memory()


print("\nFinished!")

# memory and fps will take at least 1 second to catch _stop_event
# to make function run faster, we not using self._wg.wait(..) here
# > self._wg.wait(timeout=3.0) # wait all stopped
Expand Down

0 comments on commit 29d6d16

Please sign in to comment.