-
Notifications
You must be signed in to change notification settings - Fork 1
/
run_metrics_measurements.py
executable file
·218 lines (165 loc) · 9.71 KB
/
run_metrics_measurements.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
import os
import subprocess
from time import sleep
from datetime import datetime
from utils.settings import applications, adb, deviceId, runsCount
from utils.setup import before_app_experiment, before, after, start_scenario
SCRIPTS_ON_PHONE = "/data/local/tmp/"
SAMPLING_TIME_FOR_MEMORY_IN_SECONDS = 1
SAMPLING_TIME_FOR_TEMPERATURE_IN_SECONDS = 1
SAMPLING_TIME_FOR_CPU_IN_SECONDS = 1
MEMINFO_OUTPUT_ON_PHONE = "/data/local/tmp/meminfo.dat"
THERMALINFO_OUTPUT_ON_PHONE = "/data/local/tmp/thermalinfo.dat"
TOPINFO_OUTPUT_ON_PHONE = "/data/local/tmp/topinfo.dat"
TCPDUMP_OUTPUT_ON_PHONE = '/data/local/tmp/network.pcap'
BUFFER_SIZE_FOR_TCPDUMP = 30000
def run_metrics_experiments():
"""Runs all experiments at once.
This will run experiments on tested applications in a round-robin fashion, to
avoid applications to take any benefit from caches.
You can tune experimentation by updating `runsCount` and `applications` global
variables.
Here's what this method does in detail:
* leave some time to user to boot up tested phone;
* upload all test scenarios at once to tested phone;
* run scenarios.
"""
now = datetime.now()
print( now.strftime("Started experiments at %d-%m-%Y %H:%M:%S.") )
results_dir = before()
# Push utility script on phone
print("\n==> Push utility script on phone...")
subprocess.call("{} -s {} push {} /data/local/tmp".format(adb, deviceId, "utils/scripts/runcommand.sh"), shell=True)
# Run scenarios
for x in range(runsCount):
for app in applications:
before_app_experiment()
print("\n==> Launching run n°{} with {} application".format(x, app.name))
pids = setup_metrics(app.package_name)
# Stop sampling after scenario is over
print("====> Waiting for scenario to end...")
# Launch scenario
start_scenario(app.scenario, False)
print("====> Scenario is over.")
# Wait for phone to be reconnected to computer
sleep(4)
# Stop the application.
subprocess.call("{} -s {} shell am force-stop {}".format(adb, deviceId, app.package_name), shell=True)
# Stop metrics sampling on the phone
stop_metrics_processus(pids)
# Waiting some time to wait for metrics sampling to end
sleep(3)
# Download metrics and remove associated files from tested phone.
collect_metrics("{}/{}/{}_{}".format(results_dir, app.category, app.name.replace(" ", "_"), x))
after()
now = datetime.now()
print( now.strftime("Finished experiments at %d-%m-%Y %H:%M:%S.") )
def setup_metrics(package):
# Call to meminfo in the android phone (to measure memory)
command = "dumpsys meminfo --local " + package + ' | grep -m 1 TOTAL | sed \\"s/^/\$(date +%s) /\\"'
subprocess.call("{} -s {} shell \"sh {}/runcommand.sh {} $\'{}\' {} &\" &"
.format(
adb, deviceId,
SCRIPTS_ON_PHONE, SAMPLING_TIME_FOR_MEMORY_IN_SECONDS, command, MEMINFO_OUTPUT_ON_PHONE
),
shell=True, universal_newlines=True)
# Get the pid associated to meminfo
pid_memory = subprocess.check_output(
adb + " -s " + deviceId + " shell ps -Af --sort=+pid | grep ' dumpsys meminfo --local " + package + "' | awk '{print $2}'",
shell=True, universal_newlines=True
)
pid_memory = filter_processes_list(pid_memory, True)
print("====> Meminfo PID: " + pid_memory)
# Call to top in the android phone (to measure CPU)
subprocess.call(
"{} -s {} shell -x 'top -o %CPU,%MEM,CMDLINE -d {} | grep {} | grep -v grep > {}' &".format(
adb, deviceId, SAMPLING_TIME_FOR_CPU_IN_SECONDS, package, TOPINFO_OUTPUT_ON_PHONE),
shell=True, universal_newlines=True
)
# Get the pid associated to top
pid_top = subprocess.check_output(adb + " -s " + deviceId + " shell pgrep top", shell=True,
universal_newlines=True)
pid_top = filter_processes_list(pid_top)
print("====> Top PID: " + pid_top)
# Call to thermalservice in the android phone (to measure temperature)
command = "dumpsys thermalservice | sed -n \\'/Current temperatures from HAL:/,/Current cooling devices from " \
"HAL:/p\\' | sed \\'1d;\$d\\' | " + 'sed \\"s/^/\$(date +%s) /\\"'
subprocess.call(
"{} -s {} shell \"sh {}/runcommand.sh {} $\'{}\' {} &\" &".format(
adb, deviceId, SCRIPTS_ON_PHONE, SAMPLING_TIME_FOR_TEMPERATURE_IN_SECONDS, command,
THERMALINFO_OUTPUT_ON_PHONE),
shell=True, universal_newlines=True
)
# Get the pid associated to thermalservice
pid_thermalservice = subprocess.check_output(
adb + " -s " + deviceId + " shell ps -Af --sort=+pid | grep ' dumpsys thermalservice' | awk '{print $2}'",
shell=True, universal_newlines=True
)
pid_thermalservice = filter_processes_list(pid_thermalservice, True)
print("====> Thermalservice PID: " + pid_thermalservice)
# Call to tcpdump in the android phone (to measure network usage)
tcp_file = open(package + '.tcp_stats', 'w')
subprocess.call(adb + " -s " + deviceId + " shell su -c tcpdump -s 0 -n -B " + str(BUFFER_SIZE_FOR_TCPDUMP) + " -i wlan0 -w " + TCPDUMP_OUTPUT_ON_PHONE + " &", shell=True, universal_newlines=True, stdout=tcp_file)
tcp_file.close()
# Get the pid associated to tcpdump
pid_tcpdump = subprocess.check_output(adb + " -s " + deviceId + " shell ps -Af --sort=+pid | grep tcpdump | grep root | grep -v grep | awk '{print $2}'", shell=True, universal_newlines=True)
# If there are several pids, we pick the last one
pid_tcpdump = filter_processes_list(pid_tcpdump)
print("====> tcpdump PID: " + pid_tcpdump)
return {
"pid_memory": pid_memory,
"pid_top": pid_top,
"pid_thermalservice": pid_thermalservice,
"pid_tcpdump": pid_tcpdump
}
def stop_metrics_processus(pids):
print("====> Stopping metrics processus...")
# Kill the meminfo process
subprocess.call("{} -s {} shell kill -SIGTERM {}".format(adb, deviceId, pids['pid_memory']), shell=True, universal_newlines=True)
# Kill the top process
subprocess.call("{} -s {} shell kill -SIGTERM {}".format(adb, deviceId, pids['pid_top']), shell=True, universal_newlines=True)
# Kill the thermalservice process
subprocess.call("{} -s {} shell kill -SIGTERM {}".format(adb, deviceId, pids['pid_thermalservice']), shell=True, universal_newlines=True)
# Kill the tcpdump process
subprocess.call("{} -s {} shell su -c killall -15 tcpdump".format(adb, deviceId), shell=True, universal_newlines=True)
# print(subprocess.call("{} -s {} shell su -c kill -SIGTERM {}".format(adb, deviceId, pids['pid_tcpdump']), shell=True, universal_newlines=True))
def collect_metrics(output_files_name):
print("====> Collecting metrics from phone...")
# Download the meminfo file from the phone
subprocess.call(adb + " -s " + deviceId + " pull " + MEMINFO_OUTPUT_ON_PHONE + " " + output_files_name + '.mem', shell=True)
# Cleaning format of memory file
os.system("column -t " + output_files_name + ".mem > " + output_files_name + ".meminfo")
# Generating file containing PSS information
os.system("awk '{print $1, $3}' " + output_files_name + ".meminfo > " + output_files_name + ".pss")
# Removing temp file about memory
os.system("rm -fr " + output_files_name + ".mem")
# Delete the file generated by meminfo on phone
subprocess.call(adb + " -s " + deviceId + " shell rm " + MEMINFO_OUTPUT_ON_PHONE, shell=True)
# Download the top file from the phone
topfilename = output_files_name + ".top"
topsourcefilename = topfilename + ".source"
subprocess.call(adb + " -s " + deviceId + " pull " + TOPINFO_OUTPUT_ON_PHONE + " " + topfilename, shell=True)
# Save original top log file
os.system("mv " + topfilename + " " + topsourcefilename)
# Remove color characters from file (https://gist.github.com/stevenh512/2245881)
os.system("cat \"" + topsourcefilename + "\" | sed -r \"s/\x1B\[([0-9]{1,3}((;[0-9]{1,3})*)?)?[m|K]//g\" > " + topfilename)
# Delete the file generated by top from phone
subprocess.call(adb + " -s " + deviceId + " shell rm " + TOPINFO_OUTPUT_ON_PHONE, shell=True)
# Download the thermal file from the phone
subprocess.call(adb + " -s " + deviceId + " pull " + THERMALINFO_OUTPUT_ON_PHONE + " " + output_files_name + '.thermalinfo',
shell=True)
# Cleaning format of thermal file
os.system("column -t " + output_files_name + ".thermalinfo > " + output_files_name + ".temperature")
# Removing temp file about temperature
os.system("rm -fr " + output_files_name + ".thermalinfo")
# Delete the file generated by thermalservice on phone
subprocess.call(adb + " -s " + deviceId + " shell rm " + THERMALINFO_OUTPUT_ON_PHONE, shell=True)
# Download the tcpdump file from the phone
subprocess.call(adb + " -s " + deviceId + " pull " + TCPDUMP_OUTPUT_ON_PHONE + " " + output_files_name + '.pcap', shell=True)
# Delete the tcpdump file from phone
subprocess.call(adb + " -s " + deviceId + " shell rm " + TCPDUMP_OUTPUT_ON_PHONE, shell=True)
print("tcpdump file removed in phone")
def filter_processes_list(l, return_first = False):
pids = l.split('\n') # There's one PID per line
pids = list(filter(lambda pid: len(pid) > 0, pids)) # Remove empty PIDs
return pids[0 if return_first else -1]