diff options
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 | } | ||
