934 lines · 33.2 KB · Python
RawDownload
     def _calc_alignments_summary(self, align_helper):        # Length is being cut in 3 groups so that further addition is easier to handle.        # The length of every argument from the alignment helper is being checked if it        # is longer than the longest until now. In that case the length is being saved.        for key in db["task_info"]:            if len(str(getattr(align_helper, key))) > db["task_info"][key]:                db["task_info"][key] = len(str(getattr(align_helper, key)))        for key in db["runtime_info"]:            if len(str(getattr(align_helper, key))) > db["runtime_info"][key]:                db["runtime_info"][key] = len(str(getattr(align_helper, key)))        if args.summary_extended:            for key in db["inter_times"]:                if len(str(getattr(align_helper, key))) > db["inter_times"][key]:                    db["inter_times"][key] = len(str(getattr(align_helper, key)))      def print(self):        self._task_stats()        fmt = self._format_stats()         if not args.csv_summary:            print("\nSummary")            self._print_header()        self._column_titles()        for i in range(len(self._body)):            fd_sum.write(fmt.format(*tuple(self._body[i])) + "\n")   class Task(object):    """ The class is used to handle the information of a given task."""     def __init__(self, id, tid, cpu, comm):        self.id = id        self.tid = tid        self.cpu = cpu        self.comm = comm        self.pid = None        self._time_in = None        self._time_out = None     def schedule_in_at(self, time):        """set the time where the task was scheduled in"""        self._time_in = time     def schedule_out_at(self, time):        """set the time where the task was scheduled out"""        self._time_out = time     def time_out(self, unit="s"):        """return time where a given task was scheduled out"""        factor = time_uniter(unit)        return self._time_out * decimal.Decimal(factor)     def time_in(self, unit="s"):        """return time where a given task was scheduled in"""        factor = time_uniter(unit)        return self._time_in * decimal.Decimal(factor)     def runtime(self, unit="us"):        factor = time_uniter(unit)        return (self._time_out - self._time_in) * decimal.Decimal(factor)     def update_pid(self, pid):        self.pid = pid  def _task_id(pid, cpu):    """returns a "unique-enough" identifier, please do not change"""    return "{}-{}".format(pid, cpu)  def _filter_non_printable(unfiltered):    """comm names may contain loony chars like '\x00000'"""    filtered = ""    for char in unfiltered:        if char not in string.printable:            continue        filtered += char    return filtered  def _fmt_header():    separator, fix_csv_align = _prepare_fmt_sep()    fmt = "{{:>{}}}".format(LEN_SWITCHED_IN*fix_csv_align)    fmt += "{}{{:>{}}}".format(separator, LEN_SWITCHED_OUT*fix_csv_align)    fmt += "{}{{:>{}}}".format(separator, LEN_CPU*fix_csv_align)    fmt += "{}{{:>{}}}".format(separator, LEN_PID*fix_csv_align)    fmt += "{}{{:>{}}}".format(separator, LEN_TID*fix_csv_align)    fmt += "{}{{:>{}}}".format(separator, LEN_COMM*fix_csv_align)    fmt += "{}{{:>{}}}".format(separator, LEN_RUNTIME*fix_csv_align)    fmt += "{}{{:>{}}}".format(separator, LEN_OUT_IN*fix_csv_align)    if args.extended_times:        fmt += "{}{{:>{}}}".format(separator, LEN_OUT_OUT*fix_csv_align)        fmt += "{}{{:>{}}}".format(separator, LEN_IN_IN*fix_csv_align)        fmt += "{}{{:>{}}}".format(separator, LEN_IN_OUT*fix_csv_align)    return fmt  def _fmt_body():    separator, fix_csv_align = _prepare_fmt_sep()    decimal_precision, time_precision = _prepare_fmt_precision()    fmt = "{{}}{{:{}.{}f}}".format(LEN_SWITCHED_IN*fix_csv_align, decimal_precision)    fmt += "{}{{:{}.{}f}}".format(        separator, LEN_SWITCHED_OUT*fix_csv_align, decimal_precision    )    fmt += "{}{{:{}d}}".format(separator, LEN_CPU*fix_csv_align)    fmt += "{}{{:{}d}}".format(separator, LEN_PID*fix_csv_align)    fmt += "{}{{}}{{:{}d}}{{}}".format(separator, LEN_TID*fix_csv_align)    fmt += "{}{{}}{{:>{}}}".format(separator, LEN_COMM*fix_csv_align)    fmt += "{}{{:{}.{}f}}".format(separator, LEN_RUNTIME*fix_csv_align, time_precision)    if args.extended_times:        fmt += "{}{{:{}.{}f}}".format(separator, LEN_OUT_IN*fix_csv_align, time_precision)        fmt += "{}{{:{}.{}f}}".format(separator, LEN_OUT_OUT*fix_csv_align, time_precision)        fmt += "{}{{:{}.{}f}}".format(separator, LEN_IN_IN*fix_csv_align, time_precision)        fmt += "{}{{:{}.{}f}}{{}}".format(            separator, LEN_IN_OUT*fix_csv_align, time_precision        )    else:        fmt += "{}{{:{}.{}f}}{{}}".format(            separator, LEN_OUT_IN*fix_csv_align, time_precision        )    return fmt  def _print_header():    fmt = _fmt_header()    header = ("Switched-In", "Switched-Out", "CPU", "PID", "TID", "Comm", "Runtime",            "Time Out-In")    if args.extended_times:        header += ("Time Out-Out", "Time In-In", "Time In-Out")    fd_task.write(fmt.format(*header) + "\n")   def _print_task_finish(task):    """calculating every entry of a row and printing it immediately"""    c_row_set = ""    c_row_reset = ""    out_in = -1    out_out = -1    in_in = -1    in_out = -1    fmt = _fmt_body()    # depending on user provided highlight option we change the color    # for particular tasks    if str(task.tid) in args.highlight_tasks_map:        c_row_set = _COLORS[args.highlight_tasks_map[str(task.tid)]]        c_row_reset = _COLORS["reset"]    if task.comm in args.highlight_tasks_map:        c_row_set = _COLORS[args.highlight_tasks_map[task.comm]]        c_row_reset = _COLORS["reset"]    # grey-out entries if PID == TID, they    # are identical, no threaded model so the    # thread id (tid) do not matter    c_tid_set = ""    c_tid_reset = ""    if task.pid == task.tid:        c_tid_set = _COLORS["grey"]        c_tid_reset = _COLORS["reset"]    if task.tid in db["tid"]:        # get last task of tid        last_tid_task = db["tid"][task.tid][-1]        # feed the timespan calculate, last in tid db        # and second the current one        timespan_gap_tid = Timespans()        timespan_gap_tid.feed(last_tid_task)        timespan_gap_tid.feed(task)        out_in = timespan_gap_tid.out_in        out_out = timespan_gap_tid.out_out        in_in = timespan_gap_tid.in_in        in_out = timespan_gap_tid.in_out      if args.extended_times:        line_out = fmt.format(c_row_set, task.time_in(), task.time_out(), task.cpu,                        task.pid, c_tid_set, task.tid, c_tid_reset, c_row_set, task.comm,                        task.runtime(time_unit), out_in, out_out, in_in, in_out,                        c_row_reset) + "\n"    else:        line_out = fmt.format(c_row_set, task.time_in(), task.time_out(), task.cpu,                        task.pid, c_tid_set, task.tid, c_tid_reset, c_row_set, task.comm,                        task.runtime(time_unit), out_in, c_row_reset) + "\n"    try:        fd_task.write(line_out)    except(IOError):        # don't mangle the output if user SIGINT this script        sys.exit() def _record_cleanup(_list):    """    no need to store more then one element if --summarize    is not enabled    """    if not args.summary and len(_list) > 1:        _list = _list[len(_list) - 1 :]  def _record_by_tid(task):    tid = task.tid    if tid not in db["tid"]:        db["tid"][tid] = []    db["tid"][tid].append(task)    _record_cleanup(db["tid"][tid])  def _record_by_cpu(task):    cpu = task.cpu    if cpu not in db["cpu"]:        db["cpu"][cpu] = []    db["cpu"][cpu].append(task)    _record_cleanup(db["cpu"][cpu])  def _record_global(task):    """record all executed task, ordered by finish chronological"""    db["global"].append(task)    _record_cleanup(db["global"])  def _handle_task_finish(tid, cpu, time, perf_sample_dict):    if tid == 0:        return    _id = _task_id(tid, cpu)    if _id not in db["running"]:        # may happen, if we missed the switch to        # event. Seen in combination with --exclude-perf        # where the start is filtered out, but not the        # switched in. Probably a bug in exclude-perf        # option.        return    task = db["running"][_id]    task.schedule_out_at(time)     # record tid, during schedule in the tid    # is not available, update now    pid = int(perf_sample_dict["sample"]["pid"])     task.update_pid(pid)    del db["running"][_id]     # print only tasks which are not being filtered and no print of trace    # for summary only, but record every task.    if not _limit_filtered(tid, pid, task.comm) and not args.summary_only:        _print_task_finish(task)    _record_by_tid(task)    _record_by_cpu(task)    _record_global(task)  def _handle_task_start(tid, cpu, comm, time):    if tid == 0:        return    if tid in args.tid_renames:        comm = args.tid_renames[tid]    _id = _task_id(tid, cpu)    if _id in db["running"]:        # handle corner cases where already running tasks        # are switched-to again - saw this via --exclude-perf        # recorded traces. We simple ignore this "second start"        # event.        return    assert _id not in db["running"]    task = Task(_id, tid, cpu, comm)    task.schedule_in_at(time)    db["running"][_id] = task  def _time_to_internal(time_ns):    """    To prevent float rounding errors we use Decimal internally    """    return decimal.Decimal(time_ns) / decimal.Decimal(1e9)  def _limit_filtered(tid, pid, comm):    if args.filter_tasks:        if str(tid) in args.filter_tasks or comm in args.filter_tasks:            return True        else:            return False    if args.limit_to_tasks:        if str(tid) in args.limit_to_tasks or comm in args.limit_to_tasks:            return False        else:            return True  def _argument_filter_sanity_check():    if args.limit_to_tasks and args.filter_tasks:        sys.exit("Error: Filter and Limit at the same time active.")    if args.extended_times and args.summary_only:        sys.exit("Error: Summary only and extended times active.")    if args.time_limit and ":" not in args.time_limit:        sys.exit(            "Error: No bound set for time limit. Please set bound by ':' e.g :123."        )    if args.time_limit and (args.summary or args.summary_only or args.summary_extended):        sys.exit("Error: Cannot set time limit and print summary")    if args.csv_summary:        args.summary = True        if args.csv == args.csv_summary:            sys.exit("Error: Chosen files for csv and csv summary are the same")    if args.csv and (args.summary_extended or args.summary) and not args.csv_summary:        sys.exit("Error: No file chosen to write summary to. Choose with --csv-summary "        "<file>")    if args.csv and args.summary_only:        sys.exit("Error: --csv chosen and --summary-only. Standard task would not be"            "written to csv file.") def _argument_prepare_check():    global time_unit, fd_task, fd_sum    if args.filter_tasks:        args.filter_tasks = args.filter_tasks.split(",")    if args.limit_to_tasks:        args.limit_to_tasks = args.limit_to_tasks.split(",")    if args.time_limit:        args.time_limit = args.time_limit.split(":")    for rename_tuple in args.rename_comms_by_tids.split(","):        tid_name = rename_tuple.split(":")        if len(tid_name) != 2:            continue        args.tid_renames[int(tid_name[0])] = tid_name[1]    args.highlight_tasks_map = dict()    for highlight_tasks_tuple in args.highlight_tasks.split(","):        tasks_color_map = highlight_tasks_tuple.split(":")        # default highlight color to red if no color set by user        if len(tasks_color_map) == 1:            tasks_color_map.append("red")        if args.highlight_tasks and tasks_color_map[1].lower() not in _COLORS:            sys.exit(                "Error: Color not defined, please choose from grey,red,green,yellow,blue,"                "violet"            )        if len(tasks_color_map) != 2:            continue        args.highlight_tasks_map[tasks_color_map[0]] = tasks_color_map[1]    time_unit = "us"    if args.ns:        time_unit = "ns"    elif args.ms:        time_unit = "ms"      fd_task = sys.stdout    if args.csv:        args.stdio_color = "never"        fd_task = open(args.csv, "w")        print("generating csv at",args.csv,)     fd_sum = sys.stdout    if args.csv_summary:        args.stdio_color = "never"        fd_sum = open(args.csv_summary, "w")        print("generating csv summary at",args.csv_summary)        if not args.csv:            args.summary_only = True  def _is_within_timelimit(time):    """    Check if a time limit was given by parameter, if so ignore the rest. If not,    process the recorded trace in its entirety.    """    if not args.time_limit:        return True    lower_time_limit = args.time_limit[0]    upper_time_limit = args.time_limit[1]    # check for upper limit    if upper_time_limit == "":        if time >= decimal.Decimal(lower_time_limit):            return True    # check for lower limit    if lower_time_limit == "":        if time <= decimal.Decimal(upper_time_limit):            return True        # quit if time exceeds upper limit. Good for big datasets        else:            quit()    if lower_time_limit != "" and upper_time_limit != "":        if (time >= decimal.Decimal(lower_time_limit) and            time <= decimal.Decimal(upper_time_limit)):            return True        # quit if time exceeds upper limit. Good for big datasets        elif time > decimal.Decimal(upper_time_limit):            quit() def _prepare_fmt_precision():    decimal_precision = 6    time_precision = 3    if args.ns:     decimal_precision = 9     time_precision = 0    return decimal_precision, time_precision def _prepare_fmt_sep():    separator = " "    fix_csv_align = 1    if args.csv or args.csv_summary:        separator = ";"        fix_csv_align = 0    return separator, fix_csv_align def trace_unhandled(event_name, context, event_fields_dict, perf_sample_dict):    pass  def trace_begin():    _parse_args()    _check_color()    _init_db()    if not args.summary_only:        _print_header() def trace_end():    if args.summary or args.summary_extended or args.summary_only:        Summary().print() def sched__sched_switch(event_name, context, common_cpu, common_secs, common_nsecs,                        common_pid, common_comm, common_callchain, prev_comm,                        prev_pid, prev_prio, prev_state, next_comm, next_pid,                        next_prio, perf_sample_dict):    # ignore common_secs & common_nsecs cause we need    # high res timestamp anyway, using the raw value is    # faster    time = _time_to_internal(perf_sample_dict["sample"]["time"])    if not _is_within_timelimit(time):        # user specific --time-limit a:b set        return     next_comm = _filter_non_printable(next_comm)    _handle_task_finish(prev_pid, common_cpu, time, perf_sample_dict)    _handle_task_start(next_pid, common_cpu, next_comm, time)

Lines 501–934 of 934. Previous lines