This file is indexed.

/usr/bin/ufo-prof is in libufo-bin 0.13.0-1.

This file is owned by root:root, with mode 0o755.

The actual contents of the file can be viewed below.

  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
#! /usr/bin/python
# -*- coding: utf-8 -*-

import os
import argparse
import json
import shutil
import math
import re
import sys
import numpy as np


CHARS = ['⣿', '⣷', '⣶', '⣦', '⣤', '⣄', '⡄', '⡀', '']


def get_terminal_size():
    if hasattr(shutil, 'get_terminal_size'):
        return shutil.get_terminal_size()

    rows, cols = os.popen('stty size', 'r').read().split()
    return (int(rows), int(cols))


def make_bars(begins, ends, total, width):
    line = ''
    previous = 0

    for i, (begin, end) in enumerate(zip(begins, ends)):
        span = float(end - begin) / total
        num_full_chars = int(math.floor(width * span))
        remaining = width * span - num_full_chars
        full_bar = CHARS[0] * num_full_chars
        remaining_bar = CHARS[int((len(CHARS) - 1)* (1 - remaining))]

        if i == 0:
            line += '{}{}'.format(full_bar, remaining_bar)
            previous = end
        else:
            spaces = ' ' * int((float(begin - previous) / total) * width)
            line += '{}{}{}'.format(spaces, full_bar, remaining_bar)
            previous = end

    return line


def analyse(fp, name_fmt_func, name_header):
    events = json.load(fp)['traceEvents']

    def select(key, where=lambda e: True):
        return [e[key] for e in events if where(e)]

    tasks = set(e['tid'] for e in events)
    starts = sorted([(t, min(select('ts', lambda e: e['tid'] == t))) for t in tasks], key=lambda t: t[1])
    ends = sorted([(t, max(select('ts', lambda e: e['tid'] == t))) for t in tasks], key=lambda t: t[1])
    tasks = [t[0] for t in starts]  # sorted task names

    start = starts[0][1]
    total = ends[-1][1] - start
    term_width = get_terminal_size()[0]

    begins = {t: select('ts', lambda e: e['tid'] == t and e['ph'] == 'B') for t in tasks}
    ends = {t: select('ts', lambda e: e['tid'] == t and e['ph'] == 'E') for t in tasks}
    times = {t: [end - begin for begin, end in zip(begins[t], ends[t])] for t in tasks}

    for task in tasks:
        name = name_fmt_func(task)
        name = name[:7] + u'…' if len(name) > 8 else name + u' ' * (8 - len(name))
        name = name.encode('utf-8')
        print('{} {}'.format(name, make_bars(begins[task], ends[task], total, term_width - 11)))

    print("\n {: <16} | {: >4} | {: >12} | {: >12} | {: >5}".format(name_header, '#', 'Total (ms)', 'Mean (ms)', '%'))
    print('-' * (16 + 4 + 12 + 12 + 9 + 10))

    for task, tt in ((task, times[task]) for task in tasks):
        name = name_fmt_func(task)
        total_time = np.sum(tt) / 1000.0
        mean_time = np.mean(tt) / 1000.0
        num_events = len(tt)
        percentage = float(np.sum(tt)) / total * 100
        fmt = ' {: <16} | {: >4} | {: >12.4f} | {: >12.4f} | {: >3.2f}'
        print(fmt.format(name, num_events, total_time, mean_time, percentage))


def analyse_trace(fp):
    def relevant_name(task):
        return re.match(r'Ufo([A-Za-z]*)Task-[a-f0-9x]*', task).group(1)

    analyse(fp, relevant_name, 'Task')


def analyse_opencl(fp):
    analyse(fp, lambda x: x, 'Kernel')


def main():
    parser = argparse.ArgumentParser()

    def open_valid_file(arg):
        if not os.path.exists(arg):
            parser.error("`{}' does not exist.".format(arg))
        else:
            return open(arg, 'r'), arg

    group = parser.add_mutually_exclusive_group(required=False)
    group.add_argument('--trace', action='store_true', default=None, help="JSON input is a trace file")
    group.add_argument('--opencl', action='store_true', default=None, help="JSON input is OpenCL trace")

    parser.add_argument('input', type=open_valid_file)

    args = parser.parse_args()

    if args.trace or re.match(r'trace\..*\.json', args.input[1]):
        analyse_trace(args.input[0])
        sys.exit(0)

    if args.opencl or re.match(r'opencl\..*\.json', args.input[1]):
        analyse_opencl(args.input[0])
        sys.exit(0)

    print("Could not guess trace file type, please supply --trace or --opencl.")


if __name__ == '__main__':
    main()