diff options
author | Bjoern B. Brandenburg <bbb@cs.unc.edu> | 2009-04-14 23:32:47 -0400 |
---|---|---|
committer | Bjoern B. Brandenburg <bbb@cs.unc.edu> | 2009-04-14 23:32:47 -0400 |
commit | bc15693803e84200237e6d342e2517f1d9408884 (patch) | |
tree | ca6911b31303ca6538643ed9c7f7e3d5d68e0256 | |
parent | 5fccfad62365fdeab9bbe2487760542becc2b5bb (diff) |
make sched_trace independent from liblitmus and the kernel
This is in preparation of integration with libcairo, which
isn't available as a 64bit build on Flare.
This change will also allow us to use sched_trace tools on
systems that do not have a properly configured kernel lying around
(e.g., department machines).
-rw-r--r-- | SConstruct | 32 | ||||
-rw-r--r-- | include/sched_trace.h | 127 | ||||
-rw-r--r-- | src/cairo_test.c | 41 | ||||
-rw-r--r-- | src/util.c | 133 |
4 files changed, 314 insertions, 19 deletions
@@ -1,13 +1,11 @@ | |||
1 | # ##################################################################### | 1 | # ##################################################################### |
2 | # User configuration. | 2 | # User configuration. |
3 | LITMUS_KERNEL = '../litmus2008' | 3 | # -- Nothing to configure at the moment. |
4 | LIBLITMUS = '../liblitmus2008' | ||
5 | 4 | ||
6 | # ##################################################################### | 5 | # ##################################################################### |
7 | # Internal configuration. | 6 | # Internal configuration. |
8 | DEBUG_FLAGS = '-Wall -g -Wdeclaration-after-statement' | 7 | DEBUG_FLAGS = '-Wall -g -Wdeclaration-after-statement' |
9 | INCLUDE_DIRS = 'include/ %s/include/ %s/include/' % (LITMUS_KERNEL, LIBLITMUS) | 8 | INCLUDE_DIRS = 'include/' |
10 | |||
11 | # ##################################################################### | 9 | # ##################################################################### |
12 | # Build configuration. | 10 | # Build configuration. |
13 | from os import uname | 11 | from os import uname |
@@ -18,25 +16,21 @@ if os != 'Linux': | |||
18 | print 'Error: Building sched_trace tools is only supported on Linux.' | 16 | print 'Error: Building sched_trace tools is only supported on Linux.' |
19 | Exit(1) | 17 | Exit(1) |
20 | 18 | ||
21 | if arch not in ('sparc64', 'i686'): | 19 | # base config |
22 | print 'Error: Building sched_trace tools is only supported on i686 and sparc64.' | 20 | env = Environment( |
23 | Exit(1) | ||
24 | |||
25 | st = Environment( | ||
26 | CC = 'gcc', | 21 | CC = 'gcc', |
27 | CPPPATH = Split(INCLUDE_DIRS), | ||
28 | CCFLAGS = Split(DEBUG_FLAGS), | 22 | CCFLAGS = Split(DEBUG_FLAGS), |
29 | LIBS = 'st', | 23 | CPPPATH = Split(INCLUDE_DIRS), |
30 | LIBPATH = LIBLITMUS | ||
31 | ) | 24 | ) |
32 | 25 | ||
33 | if arch == 'sparc64': | 26 | # Link with libcairo. For now without sched_trace support. |
34 | # build 64 bit sparc v9 binaries | 27 | cairo = env.Clone() |
35 | v9 = Split('-mcpu=v9 -m64') | 28 | cairo.ParseConfig('pkg-config --cflags --libs cairo') |
36 | st.Append(CCFLAGS = v9, LINKFLAGS = v9) | ||
37 | 29 | ||
38 | # ##################################################################### | 30 | # ##################################################################### |
39 | # Targets: sched_trace tools | 31 | # Targets: sched_trace tools |
40 | common = ['src/load.c', 'src/eheap.c'] | 32 | common = ['src/load.c', 'src/eheap.c', 'src/util.c'] |
41 | st.Program('st_convert', ['src/st2pl.c'] + common) | 33 | env.Program('st_convert', ['src/st2pl.c'] + common) |
42 | st.Program('st_show', ['src/showst.c'] + common) | 34 | env.Program('st_show', ['src/showst.c'] + common) |
35 | |||
36 | cairo.Program('cairo_test', ['src/cairo_test.c']) | ||
diff --git a/include/sched_trace.h b/include/sched_trace.h new file mode 100644 index 0000000..8bdd253 --- /dev/null +++ b/include/sched_trace.h | |||
@@ -0,0 +1,127 @@ | |||
1 | #ifndef __SCHED_TRACE_H_ | ||
2 | #define __SCHED_TRACE_H_ | ||
3 | |||
4 | #include <stdint.h> | ||
5 | |||
6 | typedef uint8_t u8; | ||
7 | typedef uint32_t u32; | ||
8 | typedef uint16_t u16; | ||
9 | typedef uint64_t u64; | ||
10 | |||
11 | /* A couple of notes about the format: | ||
12 | * | ||
13 | * - make sure it is in sync with the kernel | ||
14 | * - all times in nanoseconds | ||
15 | * - endianess issues are the problem of the app | ||
16 | */ | ||
17 | |||
18 | struct st_trace_header { | ||
19 | u8 type; /* Of what type is this record? */ | ||
20 | u8 cpu; /* On which CPU was it recorded? */ | ||
21 | u16 pid; /* PID of the task. */ | ||
22 | u32 job; /* The job sequence number. */ | ||
23 | }; | ||
24 | |||
25 | #define ST_NAME_LEN 16 | ||
26 | struct st_name_data { | ||
27 | char cmd[ST_NAME_LEN];/* The name of the executable of this process. */ | ||
28 | }; | ||
29 | |||
30 | struct st_param_data { /* regular params */ | ||
31 | u32 wcet; | ||
32 | u32 period; | ||
33 | u32 phase; | ||
34 | u8 partition; | ||
35 | u8 __unused[3]; | ||
36 | }; | ||
37 | |||
38 | struct st_release_data { /* A job is was/is going to be released. */ | ||
39 | u64 release; /* What's the release time? */ | ||
40 | u64 deadline; /* By when must it finish? */ | ||
41 | }; | ||
42 | |||
43 | struct st_assigned_data { /* A job was asigned to a CPU. */ | ||
44 | u64 when; | ||
45 | u8 target; /* Where should it execute? */ | ||
46 | u8 __unused[3]; | ||
47 | }; | ||
48 | |||
49 | struct st_switch_to_data { /* A process was switched to on a given CPU. */ | ||
50 | u64 when; /* When did this occur? */ | ||
51 | u32 exec_time; /* Time the current job has executed. */ | ||
52 | |||
53 | }; | ||
54 | |||
55 | struct st_switch_away_data { /* A process was switched away from on a given CPU. */ | ||
56 | u64 when; | ||
57 | u64 exec_time; | ||
58 | }; | ||
59 | |||
60 | struct st_completion_data { /* A job completed. */ | ||
61 | u64 when; | ||
62 | u8 forced:1; /* Set to 1 if job overran and kernel advanced to the | ||
63 | * next task automatically; set to 0 otherwise. | ||
64 | */ | ||
65 | u8 __uflags:7; | ||
66 | u8 __unused[3]; | ||
67 | }; | ||
68 | |||
69 | struct st_block_data { /* A task blocks. */ | ||
70 | u64 when; | ||
71 | u64 __unused; | ||
72 | }; | ||
73 | |||
74 | struct st_resume_data { /* A task resumes. */ | ||
75 | u64 when; | ||
76 | u64 __unused; | ||
77 | }; | ||
78 | |||
79 | struct st_sys_release_data { | ||
80 | u64 when; | ||
81 | u64 release; | ||
82 | }; | ||
83 | |||
84 | #define DATA(x) struct st_ ## x ## _data x; | ||
85 | |||
86 | typedef enum { | ||
87 | ST_NAME = 1, /* Start at one, so that we can spot | ||
88 | * uninitialized records. */ | ||
89 | ST_PARAM, | ||
90 | ST_RELEASE, | ||
91 | ST_ASSIGNED, | ||
92 | ST_SWITCH_TO, | ||
93 | ST_SWITCH_AWAY, | ||
94 | ST_COMPLETION, | ||
95 | ST_BLOCK, | ||
96 | ST_RESUME, | ||
97 | ST_SYS_RELEASE, | ||
98 | } st_event_record_type_t; | ||
99 | |||
100 | struct st_event_record { | ||
101 | struct st_trace_header hdr; | ||
102 | union { | ||
103 | u64 raw[2]; | ||
104 | |||
105 | DATA(name); | ||
106 | DATA(param); | ||
107 | DATA(release); | ||
108 | DATA(assigned); | ||
109 | DATA(switch_to); | ||
110 | DATA(switch_away); | ||
111 | DATA(completion); | ||
112 | DATA(block); | ||
113 | DATA(resume); | ||
114 | DATA(sys_release); | ||
115 | |||
116 | } data; | ||
117 | }; | ||
118 | |||
119 | #undef DATA | ||
120 | |||
121 | const char* event2name(unsigned int id); | ||
122 | u64 event_time(struct st_event_record* rec); | ||
123 | |||
124 | void print_event(struct st_event_record *rec); | ||
125 | void print_all(struct st_event_record *rec, unsigned int count); | ||
126 | |||
127 | #endif | ||
diff --git a/src/cairo_test.c b/src/cairo_test.c new file mode 100644 index 0000000..9c3683a --- /dev/null +++ b/src/cairo_test.c | |||
@@ -0,0 +1,41 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <stdlib.h> | ||
3 | |||
4 | #include <cairo.h> | ||
5 | |||
6 | static double in2pts(double in) | ||
7 | { | ||
8 | /* 72 pts per inch */ | ||
9 | return in * 72; | ||
10 | } | ||
11 | |||
12 | static double cm2in(double cm) | ||
13 | { | ||
14 | /* 1in = 2.54 cm */ | ||
15 | return cm / 2.54; | ||
16 | } | ||
17 | |||
18 | static double cm2pts(double cm) | ||
19 | { | ||
20 | return in2pts(cm2in(cm)); | ||
21 | } | ||
22 | |||
23 | void cairo_test(void) | ||
24 | { | ||
25 | cairo_surface_t *surface; | ||
26 | cairo_t *cr; | ||
27 | |||
28 | surface = cairo_pdf_surface_create("test.pdf", cm2pts(10), cm2pts(10)); | ||
29 | cr = cairo_create(surface); | ||
30 | cairo_set_source_rgb(cr, 1.0, 0.3, 0.7); | ||
31 | cairo_rectangle(cr, cm2pts(0.25), cm2pts(0.25), cm2pts(0.5), cm2pts(0.5)); | ||
32 | cairo_fill(cr); | ||
33 | cairo_destroy(cr); | ||
34 | cairo_surface_destroy(surface); | ||
35 | } | ||
36 | |||
37 | int main (int argc, char** argv) | ||
38 | { | ||
39 | cairo_test(); | ||
40 | return 0; | ||
41 | } | ||
diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..b603c4a --- /dev/null +++ b/src/util.c | |||
@@ -0,0 +1,133 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <stdlib.h> | ||
3 | |||
4 | |||
5 | #include <sys/types.h> | ||
6 | #include <sys/stat.h> | ||
7 | #include <sys/mman.h> | ||
8 | #include <fcntl.h> | ||
9 | #include <unistd.h> | ||
10 | |||
11 | #include "sched_trace.h" | ||
12 | |||
13 | static const char* event_names[] = { | ||
14 | "INVALID", | ||
15 | "NAME", | ||
16 | "PARAM", | ||
17 | "RELEASE", | ||
18 | "ASSIGNED", | ||
19 | "SWITCH_TO", | ||
20 | "SWITCH_FROM", | ||
21 | "COMPLETION", | ||
22 | "BLOCK", | ||
23 | "RESUME", | ||
24 | "SYS_RELEASE", | ||
25 | "INVALID" | ||
26 | }; | ||
27 | |||
28 | #define ST_INVALID (ST_SYS_RELEASE + 1) | ||
29 | |||
30 | |||
31 | const char* event2name(unsigned int id) | ||
32 | { | ||
33 | if (id >= ST_INVALID) | ||
34 | id = ST_INVALID; | ||
35 | return event_names[id]; | ||
36 | } | ||
37 | |||
38 | |||
39 | u64 event_time(struct st_event_record* rec) | ||
40 | { | ||
41 | u64 when; | ||
42 | switch (rec->hdr.type) { | ||
43 | /* the time stamp is encoded in the first payload u64 */ | ||
44 | case ST_RELEASE: | ||
45 | case ST_ASSIGNED: | ||
46 | case ST_SWITCH_TO: | ||
47 | case ST_SWITCH_AWAY: | ||
48 | case ST_COMPLETION: | ||
49 | case ST_BLOCK: | ||
50 | case ST_RESUME: | ||
51 | case ST_SYS_RELEASE: | ||
52 | when = rec->data.raw[0]; | ||
53 | break; | ||
54 | default: | ||
55 | /* stuff that doesn't have a time stamp should occur "early" */ | ||
56 | when = 0; | ||
57 | break; | ||
58 | }; | ||
59 | return when; | ||
60 | } | ||
61 | |||
62 | void print_header(struct st_trace_header* hdr) | ||
63 | { | ||
64 | printf("%-14s %5u/%-5u on CPU%3u ", | ||
65 | event2name(hdr->type), | ||
66 | hdr->pid, hdr->job, | ||
67 | hdr->cpu); | ||
68 | } | ||
69 | |||
70 | typedef void (*print_t)(struct st_event_record* rec); | ||
71 | |||
72 | static void print_nothing(struct st_event_record* _) | ||
73 | { | ||
74 | } | ||
75 | |||
76 | static void print_raw(struct st_event_record* rec) | ||
77 | { | ||
78 | printf(" type=%u", rec->hdr.type); | ||
79 | } | ||
80 | |||
81 | static void print_name(struct st_event_record* rec) | ||
82 | { | ||
83 | /* terminate in all cases */ | ||
84 | rec->data.name.cmd[ST_NAME_LEN - 1] = 0; | ||
85 | printf("%s", rec->data.name.cmd); | ||
86 | } | ||
87 | |||
88 | static void print_param(struct st_event_record* rec) | ||
89 | { | ||
90 | printf("T=(cost:%6.2fms, period:%6.2fms, phase:%6.2fms), part=%d", | ||
91 | rec->data.param.wcet / 1000000.0, | ||
92 | rec->data.param.period / 1000000.0, | ||
93 | rec->data.param.phase / 1000000.0,\ | ||
94 | rec->data.param.partition); | ||
95 | } | ||
96 | |||
97 | static void print_time_data2(struct st_event_record* rec) | ||
98 | { | ||
99 | printf("%6.2fms", rec->data.raw[1] / 1000000.0); | ||
100 | } | ||
101 | |||
102 | static print_t print_detail[] = { | ||
103 | print_raw, /* invalid */ | ||
104 | print_name, /* NAME */ | ||
105 | print_param, /* PARAM */ | ||
106 | print_time_data2, /* RELEASE */ | ||
107 | print_nothing, /* ASSIGNED */ | ||
108 | print_nothing, /* SWITCH_TO */ | ||
109 | print_nothing, /* SWITCH_FROM */ | ||
110 | print_nothing, /* COMPLETION */ | ||
111 | print_nothing, /* BLOCK */ | ||
112 | print_nothing, /* RESUME */ | ||
113 | print_time_data2, /* SYS_RELEASE */ | ||
114 | print_raw, /* invalid */ | ||
115 | }; | ||
116 | |||
117 | void print_event(struct st_event_record *rec) | ||
118 | { | ||
119 | unsigned int id = rec->hdr.type; | ||
120 | |||
121 | if (id >= ST_INVALID) | ||
122 | id = ST_INVALID; | ||
123 | print_header(&rec->hdr); | ||
124 | print_detail[id](rec); | ||
125 | printf("\n"); | ||
126 | } | ||
127 | |||
128 | void print_all(struct st_event_record *rec, unsigned int count) | ||
129 | { | ||
130 | unsigned int i; | ||
131 | for (i = 0; i < count; i++) | ||
132 | print_event(&rec[i]); | ||
133 | } | ||