aboutsummaryrefslogtreecommitdiffstats
path: root/st-draw
blob: f7774e502a271d9a193b0572b8f68018ad4f2beb (plain) (blame)
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
#!/usr/bin/env python

import argparse
import sys
import os.path

import cairo

from sched_trace import event_name, event_time, SchedTrace

import sched_trace.draw

def s2ns(secs):
    return secs * 1E9

def ms2ns(millis):
    return millis * 1E6

def ns2s(nanos):
    return nanos / 1E9

def parse_args():
    parser = argparse.ArgumentParser(
        description="Render a LITMUS^RT schedule trace as a PDF.")

    parser.add_argument('-o', '--output',
        help='name of the generated PDF file')

    parser.add_argument('-x', '--xscale', type=float, default=36,
        help="how many points (1/72'') per millisecond?")
    parser.add_argument('-y', '--yscale', type=float, default=72,
        help="how many points (1/72'') per task/core?")
    parser.add_argument('--margin', type=float, default=36,
        help="how many points (1/72'') of margin around the schedule?")

    parser.add_argument('--major-ticks', type=float, default=10,
        help="how many milliseconds per major tick? (zero means off)")
    parser.add_argument('--minor-ticks', type=float, default=1,
        help="how many milliseconds per minor tick? (zero means off)")

    parser.add_argument('-j', '--show-job-ids', action='store_true',
        help="show job IDs next to releases and completions")

    parser.add_argument('-f', '--from', type=float, dest='start',
        help='draw schedule starting at time TIME', metavar='TIME')
    parser.add_argument('-u', '--until', type=float, dest='end',
        help='draw schedule up to time TIME', metavar='TIME')
    parser.add_argument('-l', '--length', type=float, default=1000,
        help='draw schedule for LENGTH time units')
    parser.add_argument('-r', '--relative', action='store_true',
        help='interpret -f/-u options relative to system release')

    parser.add_argument('-v', '--verbose', action='store_true', default=False,
        help='output some information while drawing')

    parser.add_argument('file', nargs='*',
        help='the binary trace files collected with st-trace')

    return parser.parse_args()


def default_output_name(input_files):
    if not input_files:
        return 'schedule.pdf'
    candidate = input_files[0]
    for i in xrange(len(candidate)):
        if not all([f[i] == candidate[i] for f in input_files]):
            break
    candidate = os.path.basename(candidate[:i])
    if candidate.endswith('_cpu='):
        candidate = candidate.replace('_cpu=', '')
    if not candidate:
        return 'schedule.pdf'
    return candidate + '.pdf'

def main(args=sys.argv[1:]):
    opts = parse_args()

    if not opts.output:
        opts.output = default_output_name(opts.file)

    try:
        opts.file = [f for f in opts.file if os.stat(f).st_size > 0]
        trace = SchedTrace(opts.file)
    except IOError, msg:
        print 'Could not load trace files (%s)' % msg
        sys.exit(1)

    if opts.start:
        # convert from ms
        opts.start = ms2ns(opts.start)
        # check if a relative time is given
        if opts.relative:
            if trace.system_releases:
                opts.start += trace.system_releases[0]
            else:
                opts.start += trace.earliest_event_time

    if opts.end:
        # convert from ms
        opts.end = ms2ns(opts.end)
        # check if a relative time is given
        if opts.relative:
            if trace.system_releases:
                opts.end += trace.system_releases[0]
            else:
                opts.end += trace.earliest_event_time

    if not opts.start:
        if opts.end and opts.length:
            opts.start = opts.end - ms2ns(opts.length)
        elif trace.system_releases:
            opts.start = trace.system_releases[0]
        else:
            opts.start = trace.earliest_event_time

    if not opts.end:
        if opts.start and opts.length:
            opts.end = opts.start + ms2ns(opts.length)
        else:
            opts.end = trace.latest_event_time

    if opts.verbose:
        print '[II] Rendering into file: %s' % opts.output
        print '[II] Drawing %.2f seconds from time %.4fs until time %.4fs.' % \
            (ns2s(opts.end - opts.start), ns2s(opts.start), ns2s(opts.end))
        if len(trace.system_releases) == 1:
            print '[II] The trace contains a system release at time %.4fs.' % \
                (ns2s(trace.system_releases[0]))
        elif len(trace.system_releases) > 1:
            print '[!!] The trace contains multiple system releases: %s' % \
                (' '.join(['%.4fs' % ns2s(x) for x in trace.system_releases]))
        else:
            print '[II] The trace does not contain a system release.'

    sched_trace.draw.render(opts, trace)

#     for pid in trace.task_names:
#         print pid, '->', trace.task_names[pid], trace.task_wcets[pid], trace.task_periods[pid]

#     for (to, away) in trace.scheduling_intervals_in_range(trace.system_releases[0], trace.system_releases[0] + 1E9):
#         print to, away


if __name__ == '__main__':
    main()