Beispiel #1
0
 def arguments(self, time, pid, tid, args):
     thread = self.callbacks.process(pid).thread(tid)
     if thread.task_stack:
         for n, value in enumerate(args):
             thread.task_stack[-1].add_args({n: int(value)})
     else:
         message('warning', "Orphan args: " + str(args))
Beispiel #2
0
 def unpack_catapult(bindir):
     path = os.path.join(bindir, 'catapult', 'tracing')
     if os.path.exists(path):
         message('info', 'Catapult is taken from: ' + path)
         return path
     zip_path = os.path.join(bindir, 'catapult.zip')
     if os.path.exists(zip_path):
         print("Extracting catapult...")
         from zipfile import PyZipFile
         pzf = PyZipFile(zip_path)
         pzf.extractall(bindir)
         return path
     else:
         print("Error: Catapult is not found at", zip_path)
     return None
Beispiel #3
0
    def add_tid_name(self, tid, name):
        if name == 'kernel_task':
            return

        # one of the tids is equal to pid, and all threads have the same name as process (if not renamed)
        pid = self.tid_map[tid] if tid in self.tid_map else tid
        if abs(pid) < 4:
            return

        if pid not in self.pid_names:
            self.pid_names[pid] = [name]
        elif name not in self.pid_names[pid]:
            assert abs(pid) > 100
            self.pid_names[pid].append(name)
            full_name = '->'.join(self.pid_names[pid])
            message('warning', 'Pid %d name changed: %s' % (pid, full_name))
Beispiel #4
0
    def complete_task(self, type, begin, end):
        if self.args.distinct:
            if self.last_task == (type, begin, end):
                return
            self.last_task = (type, begin, end)
        assert (type in GoogleTrace.Phase)
        if begin['type'] == 7:  # frame_begin
            if 'id' not in begin:
                begin['id'] = id(
                    begin)  # Async events are groupped by cat & id
            res = self.format_task('b', 'frame', begin, {})
            if end:
                res += [',\n']
                end_begin = begin.copy()
                end_begin['time'] = end['time'] - 1000
                if 'args' in end:
                    end_begin['args'] = end['args']
                res += self.format_task('e', 'frame', end_begin, {})
        else:
            res = self.format_task(GoogleTrace.Phase[type], type, begin, end)

        if not res:
            return
        if type in [
                'task', 'counter'
        ] and 'data' in begin and 'str' in begin:  # FIXME: move closer to the place where stack is demanded
            self.handle_stack(
                begin, resolve_stack(self.args, self.tree, begin['data']),
                '%s:%s' % (begin['domain'], type))
        if self.args.debug and begin['type'] != 7:
            res = "".join(res)
            try:
                json.loads(res)
            except Exception as exc:
                import traceback
                print("\n" + exc.message + ":\n" + res + "\n")
                traceback.print_stack()
                self.format_task(GoogleTrace.Phase[type], type, begin, end)
            res += ',\n'
        else:
            res = "".join(res + [',\n'])
        self.file.write(res)
        if self.file.tell() > MAX_GT_SIZE:
            self.finish(intermediate=True)
            self.start_new_trace()
            message('warning',
                    'Chrome Trace File Limit Exceeded on %d' % end['time'])
Beispiel #5
0
    def stop(self, wait=True):
        for name, data in self.processes.items():
            print('Stopping:', name)
            pids = [data['pid']] + list(self.get_pid_children(data['pid']))
            for pid in pids:
                self.sudo_execute("kill -2 %d" % pid)
            for pid in pids:
                try:
                    os.waitpid(pid, 0)
                except:
                    pass

            if not data['proc']:
                continue
            out, err = data['proc'].communicate()
            message(None, "\n\n -= Target %s output =- {\n" % name)
            if out:
                self.log("Trace %s out:\n%s" % (name, out.decode()))
                message(None, out.strip())
            message(None, "-" * 50)
            if err:
                self.log("Trace %s err:\n%s" % (name, err.decode()), True)
                message(None, err.strip())
            message(None, "}\n\n")

            if data['proc'].returncode != 0:
                message('error', '%s(%d) has exited with error code %d check logs for details' % (name, data['pid'], data['proc'].returncode))

        for subcollector in self.subcollectors:
            print('Stopping:', subcollector)
            subcollector.collect(self, False)

        self.times.append(datetime.now())

        sys_log = os.path.join(self.args.output, 'sys_log.json')
        with open(sys_log, 'w') as file:
            cmd = 'log show --source --style json --debug --signpost'  # --last 1m --start, --end 'YYYY-MM-DD HH:MM:SS'
            cmd += self.times[1].strftime(" --end '%Y-%m-%d %H:%M:%S'")
            if self.args.ring:
                cmd += (self.times[1] - timedelta(seconds=self.args.ring)).strftime(" --start '%Y-%m-%d %H:%M:%S'")
            else:
                cmd += self.times[0].strftime(" --start '%Y-%m-%d %H:%M:%S'")
            self.execute(cmd, stdout=file)  # FIXME: get time of collection or ring size

        self.collect_system_info()
        self.collect_codes() 

        res = self.files + [sys_log]

        return res
Beispiel #6
0
def transform_dtrace(args):
    if not os.path.exists(args.input):
        message('error', 'File not found: ' + args.input)
        return []
    tree = default_tree(args)
    tree['ring_buffer'] = True
    args.no_left_overs = True
    gt = get_exporters()['gt']
    with Callbacks(args, tree) as callbacks:
        if callbacks.is_empty():
            return callbacks.get_result()
        dtrace = DTrace(args, gt, callbacks)
        size = os.path.getsize(args.input)
        with Progress(
                size, 50, "Parsing: %s (%s)" %
            (os.path.basename(args.input), format_bytes(size))) as progress:
            count = 0
            with codecs.open(args.input, 'r', 'utf-8',
                             errors='ignore') as file:
                reading_stack = None
                stack = []
                stat = None
                for line in file:
                    count += 1
                    ends_with_vt = (11 == ord(
                        line[-1])) if len(line) else False
                    #old_line = line
                    line = line.strip('\r\n')
                    #print("%d\t%s" % (count, line))
                    if not line:
                        if reading_stack:
                            dtrace.handle_stack(*(reading_stack + [stack]))
                            reading_stack = None
                            stack = []
                        continue
                    if stat is not None:
                        parts = line.split()
                        dtrace.handle_stat(parts[0], ' '.join(parts[1:-1]),
                                           parts[-1])
                        continue
                    if reading_stack:
                        if ends_with_vt:  # Vertical Tab signifies too long stack frame description
                            line += '...'
                            end_of_line = file.readline(
                            )  # it is also treated as line end by codecs.open
                            line += end_of_line.strip()
                        stack.append(line.replace('\t', ' '))
                        continue
                    parts = line.split('\t')
                    if len(parts) < 4:
                        if '-=STATS=-' in parts:
                            stat = {}
                        else:
                            message('warning', "weird line:" + line)
                        continue
                    if parts[1] in ['ustack', 'kstack', 'jstack']:
                        reading_stack = [
                            int(parts[0], 16), parts[1], parts[2],
                            parts[3].rstrip(':')
                        ]
                        continue
                    dtrace.handle_record(int(parts[0], 16), parts[1],
                                         parts[2:])
                    if not count % 1000:
                        progress.tick(file.tell())
            dtrace.finalize()
    return callbacks.get_result()
Beispiel #7
0
    def gpu_call(self, time, cmd, pid, tid, args):
        if 'PrepareQueueKMD' == cmd:
            if len(args) == 3:
                ctx_id, stamp, ctx_type = args
                ring_type, channel = '0', '0'
            else:
                ctx_id, ctx_type, ring_type, channel, stamp = args
            ctx_type = self.map_context_type(ctx_type)
            self.contexts[ctx_id] = ctx_type
            self.append_stage(ring_type, channel, int(stamp, 16), locals())
        elif 'SubmitQueueKMD' == cmd:
            if len(args) == 7:
                ctx_id, ctx_type, ring_type, channel, stamp, umd_submission_id, umd_call_count = args
            else:
                ctx_id, stamp, ctx_type, umd_submission_id, umd_call_count = args
                ring_type, channel = '0', '0'
            ctx_type = self.map_context_type(ctx_type)
            self.contexts[ctx_id] = ctx_type
            self.append_stage(ring_type, channel, int(stamp, 16), locals())
        elif 'SubmitToRing' == cmd:
            if len(args) == 4:
                ctx_id, ring_type, channel, stamp = args
            else:
                ctx_id, stamp, ring_type = args
                channel = '0'
            self.append_stage(ring_type, channel, int(stamp, 16), locals())
        elif 'SubmitBatchBuffer' == cmd:
            if len(args) == 4:
                ctx_id, ring_type, channel, stamp = args
            else:
                ctx_id, stamp, ring_type = args
                channel = '0'
            self.append_stage(ring_type, channel, int(stamp, 16), locals())
        elif 'SubmitExecList' == cmd:
            ctx_id, ring_type, channel, stamp = args
            self.append_stage(ring_type, channel, int(stamp, 16), locals())
        elif 'CompleteExecute' == cmd:
            if len(args) == 2:
                ring_type, latest_stamp = args
                channel = '0'
            else:
                ring_type, channel, latest_stamp = args
            self.complete_stage(ring_type, channel, int(latest_stamp, 16),
                                locals())
        elif 'CompleteExecList' == cmd:
            ctx_id, ring_type, channel, latest_stamp, ctx_run_time = args
            self.complete_stage(ring_type, channel, int(latest_stamp, 16),
                                locals())
        elif 'WriteStamp' == cmd:
            ctx_id, ring_type, channel, stamp = args
            self.append_stage(ring_type, channel, int(stamp, 16), locals())
        elif 'RemoveQueueKMD' == cmd:
            if len(args) == 2:
                ring_type, latest_stamp = args
                channel = '0'
            else:
                ring_type, channel, latest_stamp = args
            self.complete_stage(ring_type, channel, int(latest_stamp, 16),
                                locals())
        elif 'SwCtxCreation' == cmd:
            ctx_id, ctx_type = args
            ctx_type = self.map_context_type(ctx_type)
            self.contexts[ctx_id] = ctx_type
        elif 'SwCtxDestroy' == cmd:
            ctx_id, ctx_type = args
            ctx_type = self.map_context_type(ctx_type)
            self.contexts[ctx_id] = ctx_type
        elif 'DidFlip' == cmd:
            self.callbacks.vsync(time)
        elif 'BeginExecOnGPU' == cmd:
            cpu_time, ctx_id, ring_type, channel, stamp = args
            if cpu_time[0] == 'f':
                message('error',
                        "BeginExecOnGPU has wrong timestamp: " + str(args))
                return
            cpu_time = int(cpu_time, 16)
            if not cpu_time:
                if self.args.debug:
                    print("Warning: zero timestamp: ", cmd, args)
                return
            thread = self.callbacks.process(-1).thread(int(ctx_id, 16))
            ring = self.map_ring_type(ring_type)
            """ FIXME: fix lanes
            thread.lane('GPU:Render', 'dth').frame_begin(cpu_time, ring,args={
                'ring': ring, 'stamp': stamp, 'channel': int(channel, 16), 'ctx_id': int(ctx_id, 16)
            })
            """

            thread.task_pool[(ring_type, channel, stamp)] = thread.frame(
                "GPU (%d)" % thread.tid, 'dth').begin(cpu_time,
                                                      args={
                                                          'ring':
                                                          ring,
                                                          'stamp':
                                                          stamp,
                                                          'channel':
                                                          int(channel, 16),
                                                          'ctx_id':
                                                          int(ctx_id, 16)
                                                      })
            """
            thread.task_pool[(ring_type, channel, stamp)] = thread.task("GPU:" + ring, 'dth').begin(cpu_time, args={
                'ring': ring, 'stamp': stamp, 'channel': int(channel, 16), 'ctx_id': int(ctx_id, 16)
            })
            """
        elif 'EndExecOnGPU' == cmd:
            cpu_time, ctx_id, ring_type, channel, stamp = args
            if cpu_time[0] == 'f':
                message('error',
                        "EndExecOnGPU has wrong timestamp: " + str(args))
                return
            cpu_time = int(cpu_time, 16)
            if not cpu_time:
                if self.args.debug:
                    print("Warning: zero timestamp: ", cmd, args)
                return
            thread = self.callbacks.process(-1).thread(int(ctx_id, 16))
            if (ring_type, channel, stamp) in thread.task_pool:
                thread.task_pool[(ring_type, channel, stamp)].end(cpu_time)
                del thread.task_pool[(ring_type, channel, stamp)]
        else:
            print("Unhandled gpu_call:", cmd)
Beispiel #8
0
    def complete_stage(self, ring_type, channel, latest_stamp, data):
        stamps = self.event_tracker.setdefault((ring_type, channel), {})
        to_del = set(stamp for stamp in stamps.keys() if stamp <= latest_stamp)
        if len(
                to_del
        ) < 100:  # in old driver with GuC the CompleteExecute might be called so rare that it is not reliable at all
            for stamp, stages in stamps.items():
                if stamp <= latest_stamp:
                    verbose = ['%s(%s) %d:' % (ring_type, channel, stamp)]
                    ctx_type = None
                    old_ctx_id = None
                    changed_context = False
                    for stage in stages:
                        verbose.append(stage['cmd'])
                        if 'ctx_id' in stage:
                            changed_context = old_ctx_id and old_ctx_id != stage[
                                'ctx_id']
                            verbose.append('(%s)' %
                                           (('!' if changed_context else '') +
                                            stage['ctx_id']))
                            old_ctx_id = stage['ctx_id']
                        if 'ctx_type' in stage:
                            assert ctx_type == stage[
                                'ctx_type'] or not ctx_type or changed_context
                            ctx_type = stage['ctx_type']
                    if not ctx_type and old_ctx_id:
                        ctx_type = self.contexts[
                            old_ctx_id] if old_ctx_id in self.contexts else None
                    if ctx_type:
                        verbose.append('%s - %s' % (data['cmd'], ctx_type))
                    else:
                        verbose.append(data['cmd'])
                    message('info', 'verbose: ' + ' '.join(verbose))
                    if not changed_context:  # not sure what TODO with it yet
                        gpu_task = self.complete_gpu(stages[-1], data,
                                                     ctx_type, old_ctx_id)
                        found_submit = False
                        cpu_task = None
                        for stage in stages:
                            if stage['cmd'] in [
                                    'SubmitQueueKMD', 'WriteStamp'
                            ]:
                                found_submit = True
                                cpu_task = self.complete_cpu(
                                    stage, data, ctx_type, old_ctx_id,
                                    gpu_task)
                                break
                        for stage in stages:
                            if stage['cmd'] == 'PrepareQueueKMD':
                                self.complete_prepare(stages[0], stages[-1],
                                                      ctx_type, old_ctx_id,
                                                      cpu_task)
                                break
                        if not found_submit:
                            self.complete_cpu(stages[-1], data, ctx_type,
                                              old_ctx_id, gpu_task)
                    else:
                        message('warning',
                                'context has changed, not handled yet')
                else:
                    message('warning',
                            'timestamp order is bad, not handled yet')
        else:
            message('error',
                    'Unreliable CompleteExecutes: expect no GPU activity :(')

        for stamp in to_del:
            del stamps[stamp]
Beispiel #9
0
 def arg(self, time, pid, tid, name, value):
     thread = self.callbacks.process(pid).thread(tid)
     if thread.task_stack:
         thread.task_stack[-1].add_args({name: value})
     else:
         message('warning', "Orphan arg: %s %s" % (name, value))
Beispiel #10
0
    def handle_record(self, time, cmd, args):
        if not self.callbacks.check_time_in_limits(time, cmd == 'off'):
            return
        if cmd == 'off':
            cpu, prev_tid, prev_prio, prev_name, next_tid, next_prio, next_name = args

            # setting kernel activities of 0 priority as Idle:
            if prev_prio == '0' and prev_name == 'kernel_task':
                prev_tid = '0'
            if next_prio == '0' and next_name == 'kernel_task':
                next_tid = '0'
            prev_tid = int(prev_tid, 16)
            next_tid = int(next_tid, 16)

            self.callbacks.context_switch(
                time,
                int(cpu, 16),
                prev_tid=prev_tid,
                prev_state='S',
                next_tid=next_tid,
                prev_prio=int(prev_prio, 16),
                next_prio=int(next_prio, 16),
                prev_name=prev_name.replace(' ', '_'),
                next_name=next_name.replace(' ', '_'))
            self.add_tid_name(prev_tid, prev_name)
            self.add_tid_name(next_tid, next_name)
        elif cmd == 'wkp':
            prev_pid, prev_tid, prev_name, cpu, next_name, next_pid, next_tid, prim_type, prim_addr = args
            self.callbacks.wakeup(time,
                                  int(cpu, 16),
                                  prev_pid=int(prev_pid, 16),
                                  prev_tid=int(prev_tid, 16),
                                  next_pid=int(next_pid, 16),
                                  next_tid=int(next_tid, 16),
                                  prev_name=prev_name.replace(' ', '_'),
                                  next_name=next_name.replace(' ', '_'),
                                  sync_prim=SYNC_PRIM[int(prim_type, 16)],
                                  sync_prim_addr=int(prim_addr, 16))
        elif cmd.startswith('dtHook'):
            if not self.ignore_gpu:
                pid, tid = args[0:2]
                self.gpu_call(time, cmd[6:], int(pid, 16), int(tid, 16),
                              args[2:])
            elif cmd == 'dtHookCompleteExecute':
                self.ignore_gpu = False
        elif cmd in ['e', 'r']:
            pid, tid = args[0:2]
            self.task(time, int(pid, 16), int(tid, 16), cmd == 'e', args[2],
                      args[3], args[4:])
        elif cmd == 'm':
            pid, tid = args[0:2]
            self.marker(time, int(pid, 16), int(tid, 16), args[2], args[3],
                        args[4:])
        elif cmd == 'arg':
            pid, tid = args[0:2]
            self.arg(time, int(pid, 16), int(tid, 16), args[2],
                     '\t'.join(args[3:]))
        elif cmd == 'args':
            pid, tid = args[0:2]
            self.arguments(time, int(pid, 16), int(tid, 16), args[2:])
        elif cmd in ['ie', 'ir']:
            pid, tid = args[0:2]
            self.interrupt(time, int(pid, 16), int(tid, 16), cmd == 'ie',
                           args[2], int(args[3], 16), args[4:])
        elif cmd == 'io':
            pid, tid = args[0:2]
            self.io(time, int(pid, 16), int(tid, 16), args[2], args[3])
        else:
            handled = False
            if self.decoders:
                pid, tid = args[0:2]
                pid, tid = int(pid, 16), int(tid, 16)
                for decoder in self.decoders:
                    res = decoder.handle_record(time, pid, tid, cmd, args[2:])
                handled |= True if res else False
            if not handled:
                message('warning',
                        "unsupported cmd '%s': %s" % (str(cmd), str(args)))