Sergei Trofimov | 4e6afe9 | 2015-10-09 09:30:04 +0100 | [diff] [blame] | 1 | # Copyright 2015 ARM Limited |
| 2 | # |
| 3 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | # you may not use this file except in compliance with the License. |
| 5 | # You may obtain a copy of the License at |
| 6 | # |
| 7 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | # |
| 9 | # Unless required by applicable law or agreed to in writing, software |
| 10 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | # See the License for the specific language governing permissions and |
| 13 | # limitations under the License. |
| 14 | # |
| 15 | |
| 16 | from __future__ import division |
| 17 | import os |
Patrick Bellasi | 082a82c | 2016-01-26 15:38:44 +0000 | [diff] [blame] | 18 | import json |
Sergei Trofimov | 4e6afe9 | 2015-10-09 09:30:04 +0100 | [diff] [blame] | 19 | import time |
Patrick Bellasi | 082a82c | 2016-01-26 15:38:44 +0000 | [diff] [blame] | 20 | import re |
Sergei Trofimov | 4e6afe9 | 2015-10-09 09:30:04 +0100 | [diff] [blame] | 21 | import subprocess |
| 22 | |
| 23 | from devlib.trace import TraceCollector |
| 24 | from devlib.host import PACKAGE_BIN_DIRECTORY |
| 25 | from devlib.exception import TargetError, HostError |
| 26 | from devlib.utils.misc import check_output, which |
| 27 | |
| 28 | |
| 29 | TRACE_MARKER_START = 'TRACE_MARKER_START' |
| 30 | TRACE_MARKER_STOP = 'TRACE_MARKER_STOP' |
| 31 | OUTPUT_TRACE_FILE = 'trace.dat' |
Patrick Bellasi | 082a82c | 2016-01-26 15:38:44 +0000 | [diff] [blame] | 32 | OUTPUT_PROFILE_FILE = 'trace_stat.dat' |
Sergei Trofimov | 4e6afe9 | 2015-10-09 09:30:04 +0100 | [diff] [blame] | 33 | DEFAULT_EVENTS = [ |
| 34 | 'cpu_frequency', |
| 35 | 'cpu_idle', |
| 36 | 'sched_migrate_task', |
| 37 | 'sched_process_exec', |
| 38 | 'sched_process_fork', |
| 39 | 'sched_stat_iowait', |
| 40 | 'sched_switch', |
| 41 | 'sched_wakeup', |
| 42 | 'sched_wakeup_new', |
| 43 | ] |
| 44 | TIMEOUT = 180 |
| 45 | |
Patrick Bellasi | 082a82c | 2016-01-26 15:38:44 +0000 | [diff] [blame] | 46 | # Regexps for parsing of function profiling data |
| 47 | CPU_RE = re.compile(r' Function \(CPU([0-9]+)\)') |
| 48 | STATS_RE = re.compile(r'([^ ]*) +([0-9]+) +([0-9.]+) us +([0-9.]+) us +([0-9.]+) us') |
Sergei Trofimov | 4e6afe9 | 2015-10-09 09:30:04 +0100 | [diff] [blame] | 49 | |
| 50 | class FtraceCollector(TraceCollector): |
| 51 | |
| 52 | def __init__(self, target, |
| 53 | events=None, |
Patrick Bellasi | c5bc987 | 2016-01-26 15:05:58 +0000 | [diff] [blame] | 54 | functions=None, |
Sergei Trofimov | 4e6afe9 | 2015-10-09 09:30:04 +0100 | [diff] [blame] | 55 | buffer_size=None, |
| 56 | buffer_size_step=1000, |
Patrick Bellasi | bda7a16 | 2016-01-26 14:59:53 +0000 | [diff] [blame] | 57 | tracing_path='/sys/kernel/debug/tracing', |
Sergei Trofimov | 4e6afe9 | 2015-10-09 09:30:04 +0100 | [diff] [blame] | 58 | automark=True, |
| 59 | autoreport=True, |
| 60 | autoview=False, |
| 61 | no_install=False, |
Patrick Bellasi | d7bbad3 | 2016-01-27 15:53:20 +0000 | [diff] [blame] | 62 | strict=False, |
Sergei Trofimov | 92d9e69 | 2017-05-12 09:04:50 +0100 | [diff] [blame] | 63 | report_on_target=False, |
Sergei Trofimov | 4e6afe9 | 2015-10-09 09:30:04 +0100 | [diff] [blame] | 64 | ): |
| 65 | super(FtraceCollector, self).__init__(target) |
| 66 | self.events = events if events is not None else DEFAULT_EVENTS |
Patrick Bellasi | c5bc987 | 2016-01-26 15:05:58 +0000 | [diff] [blame] | 67 | self.functions = functions |
Sergei Trofimov | 4e6afe9 | 2015-10-09 09:30:04 +0100 | [diff] [blame] | 68 | self.buffer_size = buffer_size |
| 69 | self.buffer_size_step = buffer_size_step |
Patrick Bellasi | bda7a16 | 2016-01-26 14:59:53 +0000 | [diff] [blame] | 70 | self.tracing_path = tracing_path |
Sergei Trofimov | 4e6afe9 | 2015-10-09 09:30:04 +0100 | [diff] [blame] | 71 | self.automark = automark |
| 72 | self.autoreport = autoreport |
| 73 | self.autoview = autoview |
Sergei Trofimov | 92d9e69 | 2017-05-12 09:04:50 +0100 | [diff] [blame] | 74 | self.report_on_target = report_on_target |
| 75 | self.target_output_file = target.path.join(self.target.working_directory, OUTPUT_TRACE_FILE) |
| 76 | text_file_name = target.path.splitext(OUTPUT_TRACE_FILE)[0] + '.txt' |
| 77 | self.target_text_file = target.path.join(self.target.working_directory, text_file_name) |
Sergei Trofimov | 4e6afe9 | 2015-10-09 09:30:04 +0100 | [diff] [blame] | 78 | self.target_binary = None |
| 79 | self.host_binary = None |
| 80 | self.start_time = None |
| 81 | self.stop_time = None |
Patrick Bellasi | 78aa774 | 2016-02-25 18:46:04 +0000 | [diff] [blame] | 82 | self.event_string = None |
Patrick Bellasi | d7bbad3 | 2016-01-27 15:53:20 +0000 | [diff] [blame] | 83 | self.function_string = None |
Sergei Trofimov | 4e6afe9 | 2015-10-09 09:30:04 +0100 | [diff] [blame] | 84 | self._reset_needed = True |
| 85 | |
Patrick Bellasi | bda7a16 | 2016-01-26 14:59:53 +0000 | [diff] [blame] | 86 | # Setup tracing paths |
Patrick Bellasi | 78aa774 | 2016-02-25 18:46:04 +0000 | [diff] [blame] | 87 | self.available_events_file = self.target.path.join(self.tracing_path, 'available_events') |
Patrick Bellasi | c5bc987 | 2016-01-26 15:05:58 +0000 | [diff] [blame] | 88 | self.available_functions_file = self.target.path.join(self.tracing_path, 'available_filter_functions') |
Patrick Bellasi | bda7a16 | 2016-01-26 14:59:53 +0000 | [diff] [blame] | 89 | self.buffer_size_file = self.target.path.join(self.tracing_path, 'buffer_size_kb') |
Patrick Bellasi | 7f5a150 | 2016-01-26 15:33:21 +0000 | [diff] [blame] | 90 | self.current_tracer_file = self.target.path.join(self.tracing_path, 'current_tracer') |
Patrick Bellasi | c5bc987 | 2016-01-26 15:05:58 +0000 | [diff] [blame] | 91 | self.function_profile_file = self.target.path.join(self.tracing_path, 'function_profile_enabled') |
Patrick Bellasi | bda7a16 | 2016-01-26 14:59:53 +0000 | [diff] [blame] | 92 | self.marker_file = self.target.path.join(self.tracing_path, 'trace_marker') |
Patrick Bellasi | 7f5a150 | 2016-01-26 15:33:21 +0000 | [diff] [blame] | 93 | self.ftrace_filter_file = self.target.path.join(self.tracing_path, 'set_ftrace_filter') |
Patrick Bellasi | bda7a16 | 2016-01-26 14:59:53 +0000 | [diff] [blame] | 94 | |
Sergei Trofimov | 4e6afe9 | 2015-10-09 09:30:04 +0100 | [diff] [blame] | 95 | self.host_binary = which('trace-cmd') |
| 96 | self.kernelshark = which('kernelshark') |
| 97 | |
| 98 | if not self.target.is_rooted: |
| 99 | raise TargetError('trace-cmd instrument cannot be used on an unrooted device.') |
Sergei Trofimov | 92d9e69 | 2017-05-12 09:04:50 +0100 | [diff] [blame] | 100 | if self.autoreport and not self.report_on_target and self.host_binary is None: |
Sergei Trofimov | 4e6afe9 | 2015-10-09 09:30:04 +0100 | [diff] [blame] | 101 | raise HostError('trace-cmd binary must be installed on the host if autoreport=True.') |
| 102 | if self.autoview and self.kernelshark is None: |
| 103 | raise HostError('kernelshark binary must be installed on the host if autoview=True.') |
| 104 | if not no_install: |
| 105 | host_file = os.path.join(PACKAGE_BIN_DIRECTORY, self.target.abi, 'trace-cmd') |
| 106 | self.target_binary = self.target.install(host_file) |
| 107 | else: |
| 108 | if not self.target.is_installed('trace-cmd'): |
| 109 | raise TargetError('No trace-cmd found on device and no_install=True is specified.') |
| 110 | self.target_binary = 'trace-cmd' |
| 111 | |
Patrick Bellasi | 78aa774 | 2016-02-25 18:46:04 +0000 | [diff] [blame] | 112 | # Validate required events to be traced |
| 113 | available_events = self.target.execute( |
Patrick Bellasi | 3e6a040 | 2016-09-21 16:17:45 +0100 | [diff] [blame] | 114 | 'cat {}'.format(self.available_events_file), |
| 115 | as_root=True).splitlines() |
Patrick Bellasi | 78aa774 | 2016-02-25 18:46:04 +0000 | [diff] [blame] | 116 | selected_events = [] |
| 117 | for event in self.events: |
| 118 | # Convert globs supported by FTrace into valid regexp globs |
| 119 | _event = event |
| 120 | if event[0] != '*': |
| 121 | _event = '*' + event |
| 122 | event_re = re.compile(_event.replace('*', '.*')) |
| 123 | # Select events matching the required ones |
| 124 | if len(filter(event_re.match, available_events)) == 0: |
| 125 | message = 'Event [{}] not available for tracing'.format(event) |
| 126 | if strict: |
| 127 | raise TargetError(message) |
| 128 | self.target.logger.warning(message) |
| 129 | else: |
| 130 | selected_events.append(event) |
| 131 | # If function profiling is enabled we always need at least one event. |
| 132 | # Thus, if not other events have been specified, try to add at least |
| 133 | # a tracepoint which is always available and possibly triggered few |
| 134 | # times. |
| 135 | if self.functions and len(selected_events) == 0: |
| 136 | selected_events = ['sched_wakeup_new'] |
| 137 | self.event_string = _build_trace_events(selected_events) |
| 138 | |
Patrick Bellasi | c5bc987 | 2016-01-26 15:05:58 +0000 | [diff] [blame] | 139 | # Check for function tracing support |
| 140 | if self.functions: |
| 141 | if not self.target.file_exists(self.function_profile_file): |
| 142 | raise TargetError('Function profiling not supported. '\ |
| 143 | 'A kernel build with CONFIG_FUNCTION_PROFILER enable is required') |
| 144 | # Validate required functions to be traced |
| 145 | available_functions = self.target.execute( |
Patrick Bellasi | 3e6a040 | 2016-09-21 16:17:45 +0100 | [diff] [blame] | 146 | 'cat {}'.format(self.available_functions_file), |
| 147 | as_root=True).splitlines() |
Patrick Bellasi | d7bbad3 | 2016-01-27 15:53:20 +0000 | [diff] [blame] | 148 | selected_functions = [] |
Patrick Bellasi | c5bc987 | 2016-01-26 15:05:58 +0000 | [diff] [blame] | 149 | for function in self.functions: |
| 150 | if function not in available_functions: |
Patrick Bellasi | d7bbad3 | 2016-01-27 15:53:20 +0000 | [diff] [blame] | 151 | message = 'Function [{}] not available for profiling'.format(function) |
| 152 | if strict: |
| 153 | raise TargetError(message) |
| 154 | self.target.logger.warning(message) |
| 155 | else: |
| 156 | selected_functions.append(function) |
| 157 | self.function_string = _build_trace_functions(selected_functions) |
Patrick Bellasi | c5bc987 | 2016-01-26 15:05:58 +0000 | [diff] [blame] | 158 | |
Sergei Trofimov | 4e6afe9 | 2015-10-09 09:30:04 +0100 | [diff] [blame] | 159 | def reset(self): |
| 160 | if self.buffer_size: |
| 161 | self._set_buffer_size() |
Patrick Bellasi | 3e6a040 | 2016-09-21 16:17:45 +0100 | [diff] [blame] | 162 | self.target.execute('{} reset'.format(self.target_binary), |
| 163 | as_root=True, timeout=TIMEOUT) |
Sergei Trofimov | 4e6afe9 | 2015-10-09 09:30:04 +0100 | [diff] [blame] | 164 | self._reset_needed = False |
| 165 | |
| 166 | def start(self): |
| 167 | self.start_time = time.time() |
| 168 | if self._reset_needed: |
| 169 | self.reset() |
Patrick Bellasi | 3e6a040 | 2016-09-21 16:17:45 +0100 | [diff] [blame] | 170 | self.target.execute('{} start {}'.format(self.target_binary, self.event_string), |
| 171 | as_root=True) |
Sergei Trofimov | 4e6afe9 | 2015-10-09 09:30:04 +0100 | [diff] [blame] | 172 | if self.automark: |
| 173 | self.mark_start() |
Patrick Bellasi | a7cfd28 | 2015-11-16 17:45:33 +0000 | [diff] [blame] | 174 | if 'cpufreq' in self.target.modules: |
| 175 | self.logger.debug('Trace CPUFreq frequencies') |
| 176 | self.target.cpufreq.trace_frequencies() |
Brendan Jackman | 6cdae6b | 2016-11-01 18:21:49 +0000 | [diff] [blame] | 177 | if 'cpuidle' in self.target.modules: |
| 178 | self.logger.debug('Trace CPUIdle states') |
| 179 | self.target.cpuidle.perturb_cpus() |
Patrick Bellasi | 7f5a150 | 2016-01-26 15:33:21 +0000 | [diff] [blame] | 180 | # Enable kernel function profiling |
| 181 | if self.functions: |
Patrick Bellasi | 3e6a040 | 2016-09-21 16:17:45 +0100 | [diff] [blame] | 182 | self.target.execute('echo nop > {}'.format(self.current_tracer_file), |
| 183 | as_root=True) |
| 184 | self.target.execute('echo 0 > {}'.format(self.function_profile_file), |
| 185 | as_root=True) |
| 186 | self.target.execute('echo {} > {}'.format(self.function_string, self.ftrace_filter_file), |
| 187 | as_root=True) |
| 188 | self.target.execute('echo 1 > {}'.format(self.function_profile_file), |
| 189 | as_root=True) |
| 190 | |
Sergei Trofimov | 4e6afe9 | 2015-10-09 09:30:04 +0100 | [diff] [blame] | 191 | |
| 192 | def stop(self): |
Patrick Bellasi | 7f5a150 | 2016-01-26 15:33:21 +0000 | [diff] [blame] | 193 | # Disable kernel function profiling |
| 194 | if self.functions: |
Patrick Bellasi | 3e6a040 | 2016-09-21 16:17:45 +0100 | [diff] [blame] | 195 | self.target.execute('echo 1 > {}'.format(self.function_profile_file), |
| 196 | as_root=True) |
Patrick Bellasi | a7cfd28 | 2015-11-16 17:45:33 +0000 | [diff] [blame] | 197 | if 'cpufreq' in self.target.modules: |
| 198 | self.logger.debug('Trace CPUFreq frequencies') |
| 199 | self.target.cpufreq.trace_frequencies() |
Sergei Trofimov | 4e6afe9 | 2015-10-09 09:30:04 +0100 | [diff] [blame] | 200 | self.stop_time = time.time() |
| 201 | if self.automark: |
| 202 | self.mark_stop() |
Patrick Bellasi | 3e6a040 | 2016-09-21 16:17:45 +0100 | [diff] [blame] | 203 | self.target.execute('{} stop'.format(self.target_binary), |
| 204 | timeout=TIMEOUT, as_root=True) |
Sergei Trofimov | 4e6afe9 | 2015-10-09 09:30:04 +0100 | [diff] [blame] | 205 | self._reset_needed = True |
| 206 | |
| 207 | def get_trace(self, outfile): |
| 208 | if os.path.isdir(outfile): |
Sergei Trofimov | 7e80a38 | 2017-05-11 14:22:28 +0100 | [diff] [blame] | 209 | outfile = os.path.join(outfile, os.path.basename(self.target_output_file)) |
Sergei Trofimov | 61b1338 | 2017-05-12 09:01:45 +0100 | [diff] [blame] | 210 | self.target.execute('{0} extract -o {1}; chmod 666 {1}'.format(self.target_binary, |
| 211 | self.target_output_file), |
Sergei Trofimov | 4e6afe9 | 2015-10-09 09:30:04 +0100 | [diff] [blame] | 212 | timeout=TIMEOUT, as_root=True) |
| 213 | |
| 214 | # The size of trace.dat will depend on how long trace-cmd was running. |
| 215 | # Therefore timout for the pull command must also be adjusted |
| 216 | # accordingly. |
Patrick Bellasi | 82e951b | 2015-11-27 17:08:30 +0000 | [diff] [blame] | 217 | pull_timeout = 5 * (self.stop_time - self.start_time) |
Sergei Trofimov | 4e6afe9 | 2015-10-09 09:30:04 +0100 | [diff] [blame] | 218 | self.target.pull(self.target_output_file, outfile, timeout=pull_timeout) |
| 219 | if not os.path.isfile(outfile): |
| 220 | self.logger.warning('Binary trace not pulled from device.') |
| 221 | else: |
| 222 | if self.autoreport: |
| 223 | textfile = os.path.splitext(outfile)[0] + '.txt' |
Sergei Trofimov | 92d9e69 | 2017-05-12 09:04:50 +0100 | [diff] [blame] | 224 | if self.report_on_target: |
| 225 | self.generate_report_on_target() |
| 226 | self.target.pull(self.target_text_file, |
| 227 | textfile, timeout=pull_timeout) |
| 228 | else: |
| 229 | self.report(outfile, textfile) |
Sergei Trofimov | 4e6afe9 | 2015-10-09 09:30:04 +0100 | [diff] [blame] | 230 | if self.autoview: |
| 231 | self.view(outfile) |
| 232 | |
Patrick Bellasi | 082a82c | 2016-01-26 15:38:44 +0000 | [diff] [blame] | 233 | def get_stats(self, outfile): |
| 234 | if not self.functions: |
| 235 | return |
| 236 | |
| 237 | if os.path.isdir(outfile): |
| 238 | outfile = os.path.join(outfile, OUTPUT_PROFILE_FILE) |
| 239 | output = self.target._execute_util('ftrace_get_function_stats', |
| 240 | as_root=True) |
| 241 | |
| 242 | function_stats = {} |
| 243 | for line in output.splitlines(): |
| 244 | # Match a new CPU dataset |
| 245 | match = CPU_RE.search(line) |
| 246 | if match: |
| 247 | cpu_id = int(match.group(1)) |
| 248 | function_stats[cpu_id] = {} |
| 249 | self.logger.debug("Processing stats for CPU%d...", cpu_id) |
| 250 | continue |
| 251 | # Match a new function dataset |
| 252 | match = STATS_RE.search(line) |
| 253 | if match: |
| 254 | fname = match.group(1) |
| 255 | function_stats[cpu_id][fname] = { |
| 256 | 'hits' : int(match.group(2)), |
| 257 | 'time' : float(match.group(3)), |
| 258 | 'avg' : float(match.group(4)), |
| 259 | 's_2' : float(match.group(5)), |
| 260 | } |
| 261 | self.logger.debug(" %s: %s", |
| 262 | fname, function_stats[cpu_id][fname]) |
| 263 | |
| 264 | self.logger.debug("FTrace stats output [%s]...", outfile) |
| 265 | with open(outfile, 'w') as fh: |
| 266 | json.dump(function_stats, fh, indent=4) |
Patrick Bellasi | 32defe1 | 2016-02-23 15:52:42 +0000 | [diff] [blame] | 267 | self.logger.debug("FTrace function stats save in [%s]", outfile) |
Patrick Bellasi | 082a82c | 2016-01-26 15:38:44 +0000 | [diff] [blame] | 268 | |
| 269 | return function_stats |
| 270 | |
Sergei Trofimov | 4e6afe9 | 2015-10-09 09:30:04 +0100 | [diff] [blame] | 271 | def report(self, binfile, destfile): |
| 272 | # To get the output of trace.dat, trace-cmd must be installed |
| 273 | # This is done host-side because the generated file is very large |
| 274 | try: |
| 275 | command = '{} report {} > {}'.format(self.host_binary, binfile, destfile) |
| 276 | self.logger.debug(command) |
| 277 | process = subprocess.Popen(command, stderr=subprocess.PIPE, shell=True) |
| 278 | _, error = process.communicate() |
| 279 | if process.returncode: |
| 280 | raise TargetError('trace-cmd returned non-zero exit code {}'.format(process.returncode)) |
| 281 | if error: |
| 282 | # logged at debug level, as trace-cmd always outputs some |
| 283 | # errors that seem benign. |
| 284 | self.logger.debug(error) |
| 285 | if os.path.isfile(destfile): |
| 286 | self.logger.debug('Verifying traces.') |
| 287 | with open(destfile) as fh: |
| 288 | for line in fh: |
| 289 | if 'EVENTS DROPPED' in line: |
| 290 | self.logger.warning('Dropped events detected.') |
| 291 | break |
| 292 | else: |
| 293 | self.logger.debug('Trace verified.') |
| 294 | else: |
| 295 | self.logger.warning('Could not generate trace.txt.') |
| 296 | except OSError: |
| 297 | raise HostError('Could not find trace-cmd. Please make sure it is installed and is in PATH.') |
| 298 | |
Sergei Trofimov | 92d9e69 | 2017-05-12 09:04:50 +0100 | [diff] [blame] | 299 | def generate_report_on_target(self): |
| 300 | command = '{} report {} > {}'.format(self.target_binary, |
| 301 | self.target_output_file, |
| 302 | self.target_text_file) |
| 303 | self.target.execute(command, timeout=TIMEOUT) |
| 304 | |
Sergei Trofimov | 4e6afe9 | 2015-10-09 09:30:04 +0100 | [diff] [blame] | 305 | def view(self, binfile): |
| 306 | check_output('{} {}'.format(self.kernelshark, binfile), shell=True) |
| 307 | |
| 308 | def teardown(self): |
| 309 | self.target.remove(self.target.path.join(self.target.working_directory, OUTPUT_TRACE_FILE)) |
| 310 | |
| 311 | def mark_start(self): |
| 312 | self.target.write_value(self.marker_file, TRACE_MARKER_START, verify=False) |
| 313 | |
| 314 | def mark_stop(self): |
| 315 | self.target.write_value(self.marker_file, TRACE_MARKER_STOP, verify=False) |
| 316 | |
| 317 | def _set_buffer_size(self): |
| 318 | target_buffer_size = self.buffer_size |
| 319 | attempt_buffer_size = target_buffer_size |
| 320 | buffer_size = 0 |
| 321 | floor = 1000 if target_buffer_size > 1000 else target_buffer_size |
| 322 | while attempt_buffer_size >= floor: |
| 323 | self.target.write_value(self.buffer_size_file, attempt_buffer_size, verify=False) |
| 324 | buffer_size = self.target.read_int(self.buffer_size_file) |
| 325 | if buffer_size == attempt_buffer_size: |
| 326 | break |
| 327 | else: |
| 328 | attempt_buffer_size -= self.buffer_size_step |
| 329 | if buffer_size == target_buffer_size: |
| 330 | return |
| 331 | while attempt_buffer_size < target_buffer_size: |
| 332 | attempt_buffer_size += self.buffer_size_step |
| 333 | self.target.write_value(self.buffer_size_file, attempt_buffer_size, verify=False) |
| 334 | buffer_size = self.target.read_int(self.buffer_size_file) |
| 335 | if attempt_buffer_size != buffer_size: |
| 336 | message = 'Failed to set trace buffer size to {}, value set was {}' |
| 337 | self.logger.warning(message.format(target_buffer_size, buffer_size)) |
| 338 | break |
| 339 | |
| 340 | |
| 341 | def _build_trace_events(events): |
| 342 | event_string = ' '.join(['-e {}'.format(e) for e in events]) |
| 343 | return event_string |
| 344 | |
Patrick Bellasi | c5bc987 | 2016-01-26 15:05:58 +0000 | [diff] [blame] | 345 | def _build_trace_functions(functions): |
| 346 | function_string = " ".join(functions) |
| 347 | return function_string |