diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2012-01-30 17:40:44 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2012-01-30 17:40:44 -0500 |
commit | 10dd550fb2a71eddd0a2251664d3320a3d09e600 (patch) | |
tree | cbd2b1c1950e386f5647e4ea038e31f97cf41039 /src | |
parent | 2089e7a47d1e081cfd2b444e9ffb512732e6d082 (diff) | |
parent | 57069d06ed3b5086bf5ebd87998ae8afedbac7cc (diff) |
Merge branch 'mpi-staging' into mpi-master
Diffstat (limited to 'src')
-rw-r--r-- | src/ft2csv.c | 146 | ||||
-rw-r--r-- | src/ftcat.c | 37 | ||||
-rw-r--r-- | src/ftdump.c | 31 | ||||
-rw-r--r-- | src/ftsort.c | 206 | ||||
-rw-r--r-- | src/mapping.c | 29 | ||||
-rw-r--r-- | src/timestamp.c | 21 |
6 files changed, 404 insertions, 66 deletions
diff --git a/src/ft2csv.c b/src/ft2csv.c index cc6636f..aceeb25 100644 --- a/src/ft2csv.c +++ b/src/ft2csv.c | |||
@@ -30,23 +30,41 @@ | |||
30 | static int want_interleaved = 1; | 30 | static int want_interleaved = 1; |
31 | static int want_best_effort = 0; | 31 | static int want_best_effort = 0; |
32 | 32 | ||
33 | /* discard samples from a specific CPU */ | ||
34 | static int avoid_cpu = -1; | ||
35 | /* only use samples from a specific CPU */ | ||
36 | static int only_cpu = -1; | ||
37 | |||
33 | static unsigned int complete = 0; | 38 | static unsigned int complete = 0; |
34 | static unsigned int incomplete = 0; | 39 | static unsigned int incomplete = 0; |
35 | static unsigned int filtered = 0; | 40 | static unsigned int filtered = 0; |
36 | static unsigned int skipped = 0; | 41 | static unsigned int skipped = 0; |
37 | static unsigned int non_rt = 0; | 42 | static unsigned int non_rt = 0; |
38 | static unsigned int interleaved = 0; | 43 | static unsigned int interleaved = 0; |
44 | static unsigned int avoided = 0; | ||
39 | 45 | ||
40 | #define CYCLES_PER_US 2128 | 46 | #define CYCLES_PER_US 2128 |
41 | 47 | ||
42 | static unsigned long long threshold = CYCLES_PER_US * 1000; /* 1 ms == 1 full tick */ | 48 | static unsigned long long threshold = CYCLES_PER_US * 10000; /* 10 ms == 10 full ticks */ |
43 | 49 | ||
44 | static struct timestamp* next(struct timestamp* start, struct timestamp* end, | 50 | static struct timestamp* next(struct timestamp* start, struct timestamp* end, |
45 | int cpu) | 51 | int cpu) |
46 | { | 52 | { |
47 | struct timestamp* pos; | 53 | struct timestamp* pos; |
48 | for (pos = start; pos != end && pos->cpu != cpu; pos++); | 54 | unsigned int last_seqno = 0; |
49 | return pos != end ? pos : NULL; | 55 | |
56 | for (pos = start; pos != end; pos++) { | ||
57 | /* check for for holes in the sequence number */ | ||
58 | if (last_seqno && last_seqno + 1 != pos->seq_no) { | ||
59 | /* stumbled across a hole */ | ||
60 | return NULL; | ||
61 | } | ||
62 | last_seqno = pos->seq_no; | ||
63 | |||
64 | if (pos->cpu == cpu) | ||
65 | return pos; | ||
66 | } | ||
67 | return NULL; | ||
50 | } | 68 | } |
51 | 69 | ||
52 | static struct timestamp* next_id(struct timestamp* start, struct timestamp* end, | 70 | static struct timestamp* next_id(struct timestamp* start, struct timestamp* end, |
@@ -79,10 +97,35 @@ static struct timestamp* find_second_ts(struct timestamp* start, | |||
79 | start->event); | 97 | start->event); |
80 | } | 98 | } |
81 | 99 | ||
100 | typedef void (*pair_fmt_t)(struct timestamp* first, struct timestamp* second); | ||
101 | |||
102 | static void print_pair_csv(struct timestamp* first, struct timestamp* second) | ||
103 | { | ||
104 | printf("%llu, %llu, %llu\n", | ||
105 | (unsigned long long) first->timestamp, | ||
106 | (unsigned long long) second->timestamp, | ||
107 | (unsigned long long) | ||
108 | (second->timestamp - first->timestamp)); | ||
109 | } | ||
110 | |||
111 | static void print_pair_bin(struct timestamp* first, struct timestamp* second) | ||
112 | { | ||
113 | float delta = second->timestamp - first->timestamp; | ||
114 | fwrite(&delta, sizeof(delta), 1, stdout); | ||
115 | } | ||
116 | |||
117 | pair_fmt_t format_pair = print_pair_csv; | ||
118 | |||
82 | static void show_csv(struct timestamp* first, struct timestamp *end) | 119 | static void show_csv(struct timestamp* first, struct timestamp *end) |
83 | { | 120 | { |
84 | struct timestamp *second; | 121 | struct timestamp *second; |
85 | 122 | ||
123 | if (first->cpu == avoid_cpu || | ||
124 | (only_cpu != -1 && first->cpu != only_cpu)) { | ||
125 | avoided++; | ||
126 | return; | ||
127 | } | ||
128 | |||
86 | second = find_second_ts(first, end); | 129 | second = find_second_ts(first, end); |
87 | if (second) { | 130 | if (second) { |
88 | if (second->timestamp - first->timestamp > threshold) | 131 | if (second->timestamp - first->timestamp > threshold) |
@@ -91,45 +134,40 @@ static void show_csv(struct timestamp* first, struct timestamp *end) | |||
91 | second->task_type != TSK_RT && !want_best_effort) | 134 | second->task_type != TSK_RT && !want_best_effort) |
92 | non_rt++; | 135 | non_rt++; |
93 | else { | 136 | else { |
94 | printf("%llu, %llu, %llu\n", | 137 | format_pair(first, second); |
95 | (unsigned long long) first->timestamp, | ||
96 | (unsigned long long) second->timestamp, | ||
97 | (unsigned long long) | ||
98 | (second->timestamp - first->timestamp)); | ||
99 | complete++; | 138 | complete++; |
100 | } | 139 | } |
101 | } else | 140 | } else |
102 | incomplete++; | 141 | incomplete++; |
103 | |||
104 | } | 142 | } |
105 | 143 | ||
106 | static inline uint64_t bget(int x, uint64_t quad) | 144 | typedef void (*single_fmt_t)(struct timestamp* ts); |
107 | 145 | ||
146 | static void print_single_csv(struct timestamp* ts) | ||
108 | { | 147 | { |
109 | return (((0xffll << 8 * x) & quad) >> 8 * x); | 148 | printf("0, 0, %llu\n", |
149 | (unsigned long long) (ts->timestamp)); | ||
110 | } | 150 | } |
111 | 151 | ||
112 | static inline uint64_t bput(uint64_t b, int pos) | 152 | static void print_single_bin(struct timestamp* ts) |
113 | { | 153 | { |
114 | return (b << 8 * pos); | 154 | float delta = ts->timestamp; |
115 | } | ||
116 | 155 | ||
117 | static inline uint64_t ntohx(uint64_t q) | 156 | fwrite(&delta, sizeof(delta), 1, stdout); |
118 | { | ||
119 | return (bput(bget(0, q), 7) | bput(bget(1, q), 6) | | ||
120 | bput(bget(2, q), 5) | bput(bget(3, q), 4) | | ||
121 | bput(bget(4, q), 3) | bput(bget(5, q), 2) | | ||
122 | bput(bget(6, q), 1) | bput(bget(7, q), 0)); | ||
123 | } | 157 | } |
124 | 158 | ||
125 | static void restore_byte_order(struct timestamp* start, struct timestamp* end) | 159 | single_fmt_t single_fmt = print_single_csv; |
160 | |||
161 | static void show_single(struct timestamp* ts) | ||
126 | { | 162 | { |
127 | struct timestamp* pos = start; | 163 | if (ts->cpu == avoid_cpu || |
128 | while (pos !=end) { | 164 | (only_cpu != -1 && ts->cpu != only_cpu)) { |
129 | pos->timestamp = ntohx(pos->timestamp); | 165 | avoided++; |
130 | pos->seq_no = ntohl(pos->seq_no); | 166 | } else if (ts->task_type == TSK_RT) { |
131 | pos++; | 167 | single_fmt(ts); |
132 | } | 168 | complete++; |
169 | } else | ||
170 | non_rt++; | ||
133 | } | 171 | } |
134 | 172 | ||
135 | static void show_id(struct timestamp* start, struct timestamp* end, | 173 | static void show_id(struct timestamp* start, struct timestamp* end, |
@@ -145,12 +183,22 @@ static void show_id(struct timestamp* start, struct timestamp* end, | |||
145 | show_csv(start, end); | 183 | show_csv(start, end); |
146 | } | 184 | } |
147 | 185 | ||
148 | #define USAGE \ | 186 | static void show_single_records(struct timestamp* start, struct timestamp* end, |
149 | "Usage: ft2csv [-e] [-i] [-b] <event_name> <logfile> \n" \ | 187 | unsigned long id) |
150 | " -e: endianess swap -- restores byte order \n" \ | 188 | { |
151 | " -i: ignore interleaved -- ignore samples if start " \ | 189 | for (; start != end; start++) |
152 | "and end are non-consecutive\n" \ | 190 | if (start->event == id) |
191 | show_single(start); | ||
192 | } | ||
193 | |||
194 | #define USAGE \ | ||
195 | "Usage: ft2csv [-r] [-i] [-b] [-a CPU] [-o CPU] <event_name> <logfile> \n" \ | ||
196 | " -i: ignore interleaved -- ignore samples if start " \ | ||
197 | "and end are non-consecutive\n" \ | ||
153 | " -b: best effort -- don't skip non-rt time stamps \n" \ | 198 | " -b: best effort -- don't skip non-rt time stamps \n" \ |
199 | " -r: raw binary format -- don't produce .csv output \n" \ | ||
200 | " -a: avoid CPU -- skip samples from a specific CPU\n" \ | ||
201 | " -o: only CPU -- skip all samples from other CPUs\n" \ | ||
154 | "" | 202 | "" |
155 | 203 | ||
156 | static void die(char* msg) | 204 | static void die(char* msg) |
@@ -162,7 +210,7 @@ static void die(char* msg) | |||
162 | exit(1); | 210 | exit(1); |
163 | } | 211 | } |
164 | 212 | ||
165 | #define OPTS "eib" | 213 | #define OPTS "ibra:o:" |
166 | 214 | ||
167 | int main(int argc, char** argv) | 215 | int main(int argc, char** argv) |
168 | { | 216 | { |
@@ -170,21 +218,35 @@ int main(int argc, char** argv) | |||
170 | size_t size, count; | 218 | size_t size, count; |
171 | struct timestamp *ts, *end; | 219 | struct timestamp *ts, *end; |
172 | cmd_t id; | 220 | cmd_t id; |
173 | int swap_byte_order = 0; | ||
174 | int opt; | 221 | int opt; |
175 | char event_name[80]; | 222 | char event_name[80]; |
176 | 223 | ||
177 | while ((opt = getopt(argc, argv, OPTS)) != -1) { | 224 | while ((opt = getopt(argc, argv, OPTS)) != -1) { |
178 | switch (opt) { | 225 | switch (opt) { |
179 | case 'e': | ||
180 | swap_byte_order = 1; | ||
181 | break; | ||
182 | case 'i': | 226 | case 'i': |
183 | want_interleaved = 0; | 227 | want_interleaved = 0; |
228 | fprintf(stderr, "Discarging interleaved samples.\n"); | ||
184 | break; | 229 | break; |
185 | case 'b': | 230 | case 'b': |
231 | fprintf(stderr,"Not filtering samples from best-effort" | ||
232 | " tasks.\n"); | ||
186 | want_best_effort = 1; | 233 | want_best_effort = 1; |
187 | break; | 234 | break; |
235 | case 'r': | ||
236 | fprintf(stderr, "Generating binary (raw) output.\n"); | ||
237 | single_fmt = print_single_bin; | ||
238 | format_pair = print_pair_bin; | ||
239 | break; | ||
240 | case 'a': | ||
241 | avoid_cpu = atoi(optarg); | ||
242 | fprintf(stderr, "Disarding all samples from CPU %d.\n", | ||
243 | avoid_cpu); | ||
244 | break; | ||
245 | case 'o': | ||
246 | only_cpu = atoi(optarg); | ||
247 | fprintf(stderr, "Using only samples from CPU %d.\n", | ||
248 | only_cpu); | ||
249 | break; | ||
188 | default: | 250 | default: |
189 | die("Unknown option."); | 251 | die("Unknown option."); |
190 | break; | 252 | break; |
@@ -208,20 +270,22 @@ int main(int argc, char** argv) | |||
208 | count = size / sizeof(struct timestamp); | 270 | count = size / sizeof(struct timestamp); |
209 | end = ts + count; | 271 | end = ts + count; |
210 | 272 | ||
211 | if (swap_byte_order) | 273 | if (id >= SINGLE_RECORDS_RANGE) |
212 | restore_byte_order(ts, end); | 274 | show_single_records(ts, end, id); |
213 | show_id(ts, end, id); | 275 | else |
276 | show_id(ts, end, id); | ||
214 | 277 | ||
215 | fprintf(stderr, | 278 | fprintf(stderr, |
216 | "Total : %10d\n" | 279 | "Total : %10d\n" |
217 | "Skipped : %10d\n" | 280 | "Skipped : %10d\n" |
281 | "Avoided : %10d\n" | ||
218 | "Complete : %10d\n" | 282 | "Complete : %10d\n" |
219 | "Incomplete : %10d\n" | 283 | "Incomplete : %10d\n" |
220 | "Filtered : %10d\n" | 284 | "Filtered : %10d\n" |
221 | "Non RT : %10d\n" | 285 | "Non RT : %10d\n" |
222 | "Interleaved : %10d\n", | 286 | "Interleaved : %10d\n", |
223 | (int) count, | 287 | (int) count, |
224 | skipped, complete, | 288 | skipped, avoided, complete, |
225 | incomplete, filtered, non_rt, | 289 | incomplete, filtered, non_rt, |
226 | interleaved); | 290 | interleaved); |
227 | 291 | ||
diff --git a/src/ftcat.c b/src/ftcat.c index 61e007f..685f65b 100644 --- a/src/ftcat.c +++ b/src/ftcat.c | |||
@@ -24,43 +24,52 @@ | |||
24 | #include <unistd.h> | 24 | #include <unistd.h> |
25 | #include <errno.h> | 25 | #include <errno.h> |
26 | 26 | ||
27 | #include <sys/ioctl.h> | ||
28 | |||
27 | #include "timestamp.h" | 29 | #include "timestamp.h" |
28 | 30 | ||
29 | #define MAX_EVENTS 128 | 31 | #define MAX_EVENTS 128 |
30 | 32 | ||
31 | static int fd; | 33 | static int fd; |
32 | static int event_count = 1; | 34 | static int event_count = 0; |
33 | static cmd_t ids[MAX_EVENTS]; | 35 | static cmd_t ids[MAX_EVENTS]; |
34 | static unsigned long total_bytes = 0; | 36 | static unsigned long total_bytes = 0; |
35 | 37 | ||
36 | 38 | ||
37 | static int disable_all(int fd) | 39 | static int disable_all(int fd) |
38 | { | 40 | { |
39 | int ret, size; | 41 | int disabled = 0; |
40 | ids[0] = DISABLE_CMD; | 42 | int i; |
41 | fprintf(stderr, "Disabling %d events.\n", event_count - 1); | 43 | |
42 | size = event_count * sizeof(cmd_t); | 44 | fprintf(stderr, "Disabling %d events.\n", event_count); |
43 | ret = write(fd, ids, size); | 45 | for (i = 0; i < event_count; i++) |
44 | if (ret != size) | 46 | if (ioctl(fd, DISABLE_CMD, ids[i]) < 0) |
45 | fprintf(stderr, "write = %d, meant to write %d (%m)\n", ret, size); | 47 | perror("ioctl(DISABLE_CMD)"); |
46 | return size == ret; | 48 | else |
49 | disabled++; | ||
50 | |||
51 | return disabled == event_count; | ||
47 | } | 52 | } |
48 | 53 | ||
49 | static int enable_event(int fd, char* str) | 54 | static int enable_event(int fd, char* str) |
50 | { | 55 | { |
51 | cmd_t *id; | 56 | cmd_t *id; |
52 | cmd_t cmd[2]; | 57 | int err; |
53 | 58 | ||
54 | id = ids + event_count; | 59 | id = ids + event_count; |
55 | if (!str2event(str, id)) { | 60 | if (!str2event(str, id)) { |
56 | errno = EINVAL; | 61 | errno = EINVAL; |
57 | return 0; | 62 | return 0; |
58 | } | 63 | } |
59 | |||
60 | event_count += 1; | 64 | event_count += 1; |
61 | cmd[0] = ENABLE_CMD; | 65 | |
62 | cmd[1] = id[0]; | 66 | err = ioctl(fd, ENABLE_CMD, *id); |
63 | return write(fd, cmd, sizeof(cmd)) == sizeof(cmd_t) * 2; | 67 | |
68 | if (err < 0) | ||
69 | printf("ioctl(%d, %d, %d) => %d (errno: %d)\n", fd, (int) ENABLE_CMD, *id, | ||
70 | err, errno); | ||
71 | |||
72 | return err == 0; | ||
64 | } | 73 | } |
65 | 74 | ||
66 | 75 | ||
diff --git a/src/ftdump.c b/src/ftdump.c index 599473b..1462c4d 100644 --- a/src/ftdump.c +++ b/src/ftdump.c | |||
@@ -29,10 +29,31 @@ | |||
29 | static void dump(struct timestamp* ts, size_t count) | 29 | static void dump(struct timestamp* ts, size_t count) |
30 | { | 30 | { |
31 | struct timestamp *x; | 31 | struct timestamp *x; |
32 | unsigned int last_seq = 0; | ||
33 | const char* name; | ||
32 | while (count--) { | 34 | while (count--) { |
33 | x = ts++; | 35 | x = ts++; |
34 | printf("event:%d seq:%u cpu:%d type:%d\n", | 36 | name = event2str(x->event); |
35 | (int) x->event, x->seq_no, x->cpu, x->task_type); | 37 | if (last_seq && last_seq + 1 != x->seq_no) |
38 | printf("==== non-consecutive sequence number ====\n"); | ||
39 | last_seq = x->seq_no; | ||
40 | if (name) | ||
41 | printf("%-20s seq:%u timestamp:%llu cpu:%d type:%-8s irq:%u irqc:%02u \n", | ||
42 | name, x->seq_no, | ||
43 | (unsigned long long) x->timestamp, | ||
44 | x->cpu, | ||
45 | task_type2str(x->task_type), | ||
46 | x->irq_flag, | ||
47 | x->irq_count); | ||
48 | else | ||
49 | printf("%16s:%3u seq:%u timestamp:%llu cpu:%u type:%-8s irq:%u irqc:%02u\n", | ||
50 | "event", | ||
51 | (unsigned int) x->event, x->seq_no, | ||
52 | (unsigned long long) x->timestamp, | ||
53 | x->cpu, | ||
54 | task_type2str(x->task_type), | ||
55 | x->irq_flag, | ||
56 | x->irq_count); | ||
36 | } | 57 | } |
37 | } | 58 | } |
38 | 59 | ||
@@ -57,14 +78,12 @@ int main(int argc, char** argv) | |||
57 | "\t offset(timestamp) = %3lu\n" | 78 | "\t offset(timestamp) = %3lu\n" |
58 | "\t offset(seq_no) = %3lu\n" | 79 | "\t offset(seq_no) = %3lu\n" |
59 | "\t offset(cpu) = %3lu\n" | 80 | "\t offset(cpu) = %3lu\n" |
60 | "\t offset(event) = %3lu\n" | 81 | "\t offset(event) = %3lu\n", |
61 | "\t offset(task_type) = %3lu\n", | ||
62 | (unsigned long) sizeof(struct timestamp), | 82 | (unsigned long) sizeof(struct timestamp), |
63 | offset(struct timestamp, timestamp), | 83 | offset(struct timestamp, timestamp), |
64 | offset(struct timestamp, seq_no), | 84 | offset(struct timestamp, seq_no), |
65 | offset(struct timestamp, cpu), | 85 | offset(struct timestamp, cpu), |
66 | offset(struct timestamp, event), | 86 | offset(struct timestamp, event)); |
67 | offset(struct timestamp, task_type)); | ||
68 | 87 | ||
69 | if (argc != 2) | 88 | if (argc != 2) |
70 | die("Usage: ftdump <logfile>"); | 89 | die("Usage: ftdump <logfile>"); |
diff --git a/src/ftsort.c b/src/ftsort.c new file mode 100644 index 0000000..5ddb48f --- /dev/null +++ b/src/ftsort.c | |||
@@ -0,0 +1,206 @@ | |||
1 | /* ft2sort -- Sort Feather-Trace events in a binary file by sequence number. | ||
2 | * Copyright (C) 2011 B. Brandenburg. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along | ||
15 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
17 | */ | ||
18 | #include <stdio.h> | ||
19 | #include <stdlib.h> | ||
20 | #include <string.h> | ||
21 | |||
22 | #include <time.h> | ||
23 | #include <sys/time.h> | ||
24 | |||
25 | #include <errno.h> | ||
26 | #include <unistd.h> | ||
27 | #include <arpa/inet.h> | ||
28 | #include <sys/mman.h> | ||
29 | |||
30 | #include "mapping.h" | ||
31 | |||
32 | #include "timestamp.h" | ||
33 | |||
34 | static unsigned int holes = 0; | ||
35 | static unsigned int reordered = 0; | ||
36 | |||
37 | #define LOOK_AHEAD 1000 | ||
38 | |||
39 | /* wall-clock time in seconds */ | ||
40 | double wctime(void) | ||
41 | { | ||
42 | struct timeval tv; | ||
43 | gettimeofday(&tv, NULL); | ||
44 | return (tv.tv_sec + 1E-6 * tv.tv_usec); | ||
45 | } | ||
46 | |||
47 | |||
48 | static struct timestamp* find_lowest_seq_no(struct timestamp* start, | ||
49 | struct timestamp* end, | ||
50 | unsigned int seqno) | ||
51 | { | ||
52 | struct timestamp *pos, *min = start; | ||
53 | |||
54 | if (end > start + LOOK_AHEAD) | ||
55 | end = start + LOOK_AHEAD; | ||
56 | |||
57 | for (pos = start; pos != end && min->seq_no != seqno; pos++) | ||
58 | if (pos->seq_no < min->seq_no) | ||
59 | min = pos; | ||
60 | return min; | ||
61 | } | ||
62 | |||
63 | |||
64 | static void move_record(struct timestamp* target, struct timestamp* pos) | ||
65 | { | ||
66 | struct timestamp tmp, *prev; | ||
67 | |||
68 | while (pos > target) { | ||
69 | /* shift backwards */ | ||
70 | tmp = *pos; | ||
71 | prev = pos - 1; | ||
72 | |||
73 | *pos = *prev; | ||
74 | *prev = tmp; | ||
75 | |||
76 | pos = prev; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | static void reorder(struct timestamp* start, struct timestamp* end) | ||
81 | { | ||
82 | struct timestamp* pos, *tmp; | ||
83 | unsigned int last_seqno = 0; | ||
84 | |||
85 | for (pos = start; pos != end; pos++) { | ||
86 | /* check for for holes in the sequence number */ | ||
87 | if (last_seqno && last_seqno + 1 != pos->seq_no) { | ||
88 | tmp = find_lowest_seq_no(pos, end, last_seqno + 1); | ||
89 | if (tmp->seq_no == last_seqno + 1) | ||
90 | /* Good, we found it. */ | ||
91 | /* Move it to the right place. */ | ||
92 | reordered++; | ||
93 | else { | ||
94 | /* bad, there's a hole here */ | ||
95 | holes++; | ||
96 | fprintf(stderr, "HOLE: %u instead of %u\n", tmp->seq_no, last_seqno + 1); | ||
97 | } | ||
98 | move_record(pos, tmp); | ||
99 | } | ||
100 | last_seqno = pos->seq_no; | ||
101 | } | ||
102 | } | ||
103 | |||
104 | static inline uint64_t bget(int x, uint64_t quad) | ||
105 | |||
106 | { | ||
107 | return (((0xffll << 8 * x) & quad) >> 8 * x); | ||
108 | } | ||
109 | |||
110 | static inline uint64_t bput(uint64_t b, int pos) | ||
111 | { | ||
112 | return (b << 8 * pos); | ||
113 | } | ||
114 | |||
115 | static inline uint64_t ntohx(uint64_t q) | ||
116 | { | ||
117 | return (bput(bget(0, q), 7) | bput(bget(1, q), 6) | | ||
118 | bput(bget(2, q), 5) | bput(bget(3, q), 4) | | ||
119 | bput(bget(4, q), 3) | bput(bget(5, q), 2) | | ||
120 | bput(bget(6, q), 1) | bput(bget(7, q), 0)); | ||
121 | } | ||
122 | |||
123 | static void restore_byte_order(struct timestamp* start, struct timestamp* end) | ||
124 | { | ||
125 | struct timestamp* pos = start; | ||
126 | while (pos !=end) { | ||
127 | pos->timestamp = ntohx(pos->timestamp); | ||
128 | pos->seq_no = ntohl(pos->seq_no); | ||
129 | pos++; | ||
130 | } | ||
131 | } | ||
132 | |||
133 | #define USAGE \ | ||
134 | "Usage: ftsort [-e] <logfile> \n" \ | ||
135 | " -e: endianess swap -- restores byte order \n" \ | ||
136 | "\n" \ | ||
137 | "WARNING: Changes are permanent.\n" | ||
138 | |||
139 | static void die(char* msg) | ||
140 | { | ||
141 | if (errno) | ||
142 | perror("error: "); | ||
143 | fprintf(stderr, "%s\n", msg); | ||
144 | fprintf(stderr, "%s", USAGE); | ||
145 | exit(1); | ||
146 | } | ||
147 | |||
148 | #define OPTS "e" | ||
149 | |||
150 | int main(int argc, char** argv) | ||
151 | { | ||
152 | void* mapped; | ||
153 | size_t size, count; | ||
154 | struct timestamp *ts, *end; | ||
155 | int swap_byte_order = 0; | ||
156 | int opt; | ||
157 | double start, stop; | ||
158 | |||
159 | while ((opt = getopt(argc, argv, OPTS)) != -1) { | ||
160 | switch (opt) { | ||
161 | case 'e': | ||
162 | swap_byte_order = 1; | ||
163 | break; | ||
164 | default: | ||
165 | die("Unknown option."); | ||
166 | break; | ||
167 | } | ||
168 | } | ||
169 | |||
170 | if (argc - optind != 1) | ||
171 | die("arguments missing"); | ||
172 | |||
173 | start = wctime(); | ||
174 | |||
175 | if (map_file_rw(argv[optind], &mapped, &size)) | ||
176 | die("could not map file"); | ||
177 | |||
178 | ts = (struct timestamp*) mapped; | ||
179 | count = size / sizeof(struct timestamp); | ||
180 | end = ts + count; | ||
181 | |||
182 | if (swap_byte_order) | ||
183 | restore_byte_order(ts, end); | ||
184 | |||
185 | reorder(ts, end); | ||
186 | |||
187 | /* write back */ | ||
188 | msync(ts, size, MS_SYNC | MS_INVALIDATE); | ||
189 | |||
190 | stop = wctime(); | ||
191 | |||
192 | fprintf(stderr, | ||
193 | "Total : %10d\n" | ||
194 | "Holes : %10d\n" | ||
195 | "Reordered : %10d\n" | ||
196 | "Size : %10.2f Mb\n" | ||
197 | "Time : %10.2f s\n" | ||
198 | "Throughput : %10.2f Mb/s\n", | ||
199 | (int) count, | ||
200 | holes, reordered, | ||
201 | ((double) size) / 1024.0 / 1024.0, | ||
202 | (stop - start), | ||
203 | ((double) size) / 1024.0 / 1024.0 / (stop - start)); | ||
204 | |||
205 | return 0; | ||
206 | } | ||
diff --git a/src/mapping.c b/src/mapping.c index 19d7129..e4ce96c 100644 --- a/src/mapping.c +++ b/src/mapping.c | |||
@@ -5,13 +5,16 @@ | |||
5 | #include <errno.h> | 5 | #include <errno.h> |
6 | #include <unistd.h> | 6 | #include <unistd.h> |
7 | 7 | ||
8 | #include <stdio.h> | ||
9 | |||
8 | #include "mapping.h" | 10 | #include "mapping.h" |
9 | 11 | ||
10 | int map_file(const char* filename, void **addr, size_t *size) | 12 | static int _map_file(const char* filename, void **addr, size_t *size, int writable) |
11 | { | 13 | { |
12 | struct stat info; | 14 | struct stat info; |
13 | int error = 0; | 15 | int error = 0; |
14 | int fd; | 16 | int fd; |
17 | int flags = writable ? MAP_SHARED : MAP_PRIVATE; | ||
15 | 18 | ||
16 | error = stat(filename, &info); | 19 | error = stat(filename, &info); |
17 | if (!error) { | 20 | if (!error) { |
@@ -19,12 +22,19 @@ int map_file(const char* filename, void **addr, size_t *size) | |||
19 | if (info.st_size > 0) { | 22 | if (info.st_size > 0) { |
20 | fd = open(filename, O_RDWR); | 23 | fd = open(filename, O_RDWR); |
21 | if (fd >= 0) { | 24 | if (fd >= 0) { |
22 | *addr = mmap(NULL, *size, | 25 | *addr = mmap(NULL, *size, |
23 | PROT_READ | PROT_WRITE, | 26 | PROT_READ | PROT_WRITE, |
24 | MAP_PRIVATE, | 27 | flags, |
25 | fd, 0); | 28 | fd, 0); |
26 | if (*addr == MAP_FAILED) | 29 | if (*addr == MAP_FAILED) |
27 | error = -1; | 30 | error = -1; |
31 | else { | ||
32 | /* tell kernel to start getting the pages */ | ||
33 | error = madvise(*addr, *size, MADV_SEQUENTIAL | MADV_WILLNEED); | ||
34 | if (error) { | ||
35 | perror("madvise"); | ||
36 | } | ||
37 | } | ||
28 | close(fd); | 38 | close(fd); |
29 | } else | 39 | } else |
30 | error = fd; | 40 | error = fd; |
@@ -33,3 +43,14 @@ int map_file(const char* filename, void **addr, size_t *size) | |||
33 | } | 43 | } |
34 | return error; | 44 | return error; |
35 | } | 45 | } |
46 | |||
47 | |||
48 | int map_file(const char* filename, void **addr, size_t *size) | ||
49 | { | ||
50 | return _map_file(filename, addr, size, 0); | ||
51 | } | ||
52 | |||
53 | int map_file_rw(const char* filename, void **addr, size_t *size) | ||
54 | { | ||
55 | return _map_file(filename, addr, size, 1); | ||
56 | } | ||
diff --git a/src/timestamp.c b/src/timestamp.c index 4c04ce7..442c445 100644 --- a/src/timestamp.c +++ b/src/timestamp.c | |||
@@ -22,17 +22,26 @@ static struct event_name event_table[] = | |||
22 | EVENT(PLUGIN_TICK), | 22 | EVENT(PLUGIN_TICK), |
23 | EVENT(CXS), | 23 | EVENT(CXS), |
24 | EVENT(SEND_RESCHED), | 24 | EVENT(SEND_RESCHED), |
25 | {"RELEASE_LATENCY", TS_RELEASE_LATENCY}, | ||
26 | |||
27 | EVENT(SYSCALL_IN), | ||
28 | EVENT(SYSCALL_OUT), | ||
29 | EVENT(LOCK), | ||
30 | EVENT(UNLOCK), | ||
31 | {"LOCK_SUSPEND", TS_LOCK_SUSPEND}, | ||
32 | {"LOCK_RESUME", TS_LOCK_RESUME}, | ||
25 | }; | 33 | }; |
26 | 34 | ||
27 | int str2event(const char* str, cmd_t *id) | 35 | int str2event(const char* str, cmd_t *id) |
28 | { | 36 | { |
29 | int i; | 37 | int i; |
30 | 38 | ||
31 | for (i = 0; i < sizeof(event_table) / sizeof(event_table[0]); i++) | 39 | for (i = 0; i < sizeof(event_table) / sizeof(event_table[0]); i++) { |
32 | if (!strcmp(str, event_table[i].name)) { | 40 | if (!strcmp(str, event_table[i].name)) { |
33 | *id = event_table[i].id; | 41 | *id = event_table[i].id; |
34 | return 1; | 42 | return 1; |
35 | } | 43 | } |
44 | } | ||
36 | /* try to parse it as a number */ | 45 | /* try to parse it as a number */ |
37 | return sscanf(str, "%u", id); | 46 | return sscanf(str, "%u", id); |
38 | } | 47 | } |
@@ -47,3 +56,13 @@ const char* event2str(cmd_t id) | |||
47 | 56 | ||
48 | return NULL; | 57 | return NULL; |
49 | } | 58 | } |
59 | |||
60 | const char* task_type2str(int task_type) | ||
61 | { | ||
62 | if (task_type == TSK_RT) | ||
63 | return "RT"; | ||
64 | else if (task_type == TSK_BE) | ||
65 | return "BE"; | ||
66 | else | ||
67 | return "UNKNOWN"; | ||
68 | } | ||