aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2009-09-12 21:36:29 -0400
committerIngo Molnar <mingo@elte.hu>2009-09-13 04:22:48 -0400
commitdaa1d7a5eafc0a3a91a9add6a9a9f1bcaed63108 (patch)
tree061114ddcf5247fe11f5afdec7bc3015e9fc2640
parent7362262687b21b0d04927a7615c162a3d064849e (diff)
perf sched: Implement multidimensional sorting
Implement multidimensional sorting on perf sched so that you can sort either by number of switches, latency average, latency maximum, runtime. perf sched -l -s avg,max (this is the default) ----------------------------------------------------------------------------------- Task | Runtime ms | Switches | Average delay ms | Maximum delay ms | ----------------------------------------------------------------------------------- gnome-power-man | 0.113 ms | 1 | avg: 4998.531 ms | max: 4998.531 ms | xfdesktop | 1.190 ms | 7 | avg: 136.475 ms | max: 940.933 ms | xfce-mcs-manage | 2.194 ms | 22 | avg: 38.534 ms | max: 735.174 ms | notification-da | 2.749 ms | 31 | avg: 27.436 ms | max: 731.791 ms | xfce4-session | 3.343 ms | 28 | avg: 26.796 ms | max: 734.891 ms | xfwm4 | 3.159 ms | 22 | avg: 12.406 ms | max: 241.333 ms | xchat | 42.789 ms | 214 | avg: 11.886 ms | max: 100.349 ms | xfce4-terminal | 5.386 ms | 22 | avg: 11.414 ms | max: 241.611 ms | firefox | 151.992 ms | 123 | avg: 9.543 ms | max: 153.717 ms | xfce4-panel | 24.324 ms | 47 | avg: 8.189 ms | max: 242.352 ms | :5090 | 6.932 ms | 111 | avg: 8.131 ms | max: 102.665 ms | events/0 | 0.758 ms | 12 | avg: 1.964 ms | max: 21.879 ms | Xorg | 280.558 ms | 340 | avg: 1.864 ms | max: 99.526 ms | geany | 63.391 ms | 295 | avg: 1.099 ms | max: 9.334 ms | reiserfs/0 | 0.039 ms | 2 | avg: 0.854 ms | max: 1.487 ms | kondemand/0 | 8.251 ms | 245 | avg: 0.691 ms | max: 34.372 ms | Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--tools/perf/builtin-sched.c206
1 files changed, 196 insertions, 10 deletions
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 67a0ba88aecf..10fcd49e298b 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -33,6 +33,9 @@ static u64 sample_type;
33static int replay_mode; 33static int replay_mode;
34static int lat_mode; 34static int lat_mode;
35 35
36static char default_sort_order[] = "avg, max, switch, runtime";
37static char *sort_order = default_sort_order;
38
36 39
37/* 40/*
38 * Scheduler benchmarks 41 * Scheduler benchmarks
@@ -890,7 +893,17 @@ struct task_atoms {
890 u64 total_runtime; 893 u64 total_runtime;
891}; 894};
892 895
893static struct rb_root lat_snapshot_root; 896typedef int (*sort_thread_lat)(struct task_atoms *, struct task_atoms *);
897
898struct sort_dimension {
899 const char *name;
900 sort_thread_lat cmp;
901 struct list_head list;
902};
903
904static LIST_HEAD(cmp_pid);
905
906static struct rb_root lat_snapshot_root, sorted_lat_snapshot_root;
894 907
895static struct task_atoms * 908static struct task_atoms *
896thread_atom_list_search(struct rb_root *root, struct thread *thread) 909thread_atom_list_search(struct rb_root *root, struct thread *thread)
@@ -901,9 +914,9 @@ thread_atom_list_search(struct rb_root *root, struct thread *thread)
901 struct task_atoms *atoms; 914 struct task_atoms *atoms;
902 915
903 atoms = container_of(node, struct task_atoms, node); 916 atoms = container_of(node, struct task_atoms, node);
904 if (thread->pid < atoms->thread->pid) 917 if (thread->pid > atoms->thread->pid)
905 node = node->rb_left; 918 node = node->rb_left;
906 else if (thread->pid > atoms->thread->pid) 919 else if (thread->pid < atoms->thread->pid)
907 node = node->rb_right; 920 node = node->rb_right;
908 else { 921 else {
909 return atoms; 922 return atoms;
@@ -912,22 +925,41 @@ thread_atom_list_search(struct rb_root *root, struct thread *thread)
912 return NULL; 925 return NULL;
913} 926}
914 927
928static int
929thread_lat_cmp(struct list_head *list, struct task_atoms *l,
930 struct task_atoms *r)
931{
932 struct sort_dimension *sort;
933 int ret = 0;
934
935 list_for_each_entry(sort, list, list) {
936 ret = sort->cmp(l, r);
937 if (ret)
938 return ret;
939 }
940
941 return ret;
942}
943
915static void 944static void
916__thread_latency_insert(struct rb_root *root, struct task_atoms *data) 945__thread_latency_insert(struct rb_root *root, struct task_atoms *data,
946 struct list_head *sort_list)
917{ 947{
918 struct rb_node **new = &(root->rb_node), *parent = NULL; 948 struct rb_node **new = &(root->rb_node), *parent = NULL;
919 949
920 while (*new) { 950 while (*new) {
921 struct task_atoms *this; 951 struct task_atoms *this;
952 int cmp;
922 953
923 this = container_of(*new, struct task_atoms, node); 954 this = container_of(*new, struct task_atoms, node);
924 parent = *new; 955 parent = *new;
925 if (data->thread->pid < this->thread->pid) 956
957 cmp = thread_lat_cmp(sort_list, data, this);
958
959 if (cmp > 0)
926 new = &((*new)->rb_left); 960 new = &((*new)->rb_left);
927 else if (data->thread->pid > this->thread->pid)
928 new = &((*new)->rb_right);
929 else 961 else
930 die("Double thread insertion\n"); 962 new = &((*new)->rb_right);
931 } 963 }
932 964
933 rb_link_node(&data->node, parent, new); 965 rb_link_node(&data->node, parent, new);
@@ -943,7 +975,7 @@ static void thread_atom_list_insert(struct thread *thread)
943 975
944 atoms->thread = thread; 976 atoms->thread = thread;
945 INIT_LIST_HEAD(&atoms->snapshot_list); 977 INIT_LIST_HEAD(&atoms->snapshot_list);
946 __thread_latency_insert(&lat_snapshot_root, atoms); 978 __thread_latency_insert(&lat_snapshot_root, atoms, &cmp_pid);
947} 979}
948 980
949static void 981static void
@@ -1134,18 +1166,151 @@ static void output_lat_thread(struct task_atoms *atom_list)
1134 (double)atom_list->max_lat / 1e6); 1166 (double)atom_list->max_lat / 1e6);
1135} 1167}
1136 1168
1169static int pid_cmp(struct task_atoms *l, struct task_atoms *r)
1170{
1171
1172 if (l->thread->pid < r->thread->pid)
1173 return -1;
1174 if (l->thread->pid > r->thread->pid)
1175 return 1;
1176
1177 return 0;
1178}
1179
1180static struct sort_dimension pid_sort_dimension = {
1181 .name = "pid",
1182 .cmp = pid_cmp,
1183};
1184
1185static int avg_cmp(struct task_atoms *l, struct task_atoms *r)
1186{
1187 u64 avgl, avgr;
1188
1189 if (!l->nb_atoms)
1190 return -1;
1191
1192 if (!r->nb_atoms)
1193 return 1;
1194
1195 avgl = l->total_lat / l->nb_atoms;
1196 avgr = r->total_lat / r->nb_atoms;
1197
1198 if (avgl < avgr)
1199 return -1;
1200 if (avgl > avgr)
1201 return 1;
1202
1203 return 0;
1204}
1205
1206static struct sort_dimension avg_sort_dimension = {
1207 .name = "avg",
1208 .cmp = avg_cmp,
1209};
1210
1211static int max_cmp(struct task_atoms *l, struct task_atoms *r)
1212{
1213 if (l->max_lat < r->max_lat)
1214 return -1;
1215 if (l->max_lat > r->max_lat)
1216 return 1;
1217
1218 return 0;
1219}
1220
1221static struct sort_dimension max_sort_dimension = {
1222 .name = "max",
1223 .cmp = max_cmp,
1224};
1225
1226static int switch_cmp(struct task_atoms *l, struct task_atoms *r)
1227{
1228 if (l->nb_atoms < r->nb_atoms)
1229 return -1;
1230 if (l->nb_atoms > r->nb_atoms)
1231 return 1;
1232
1233 return 0;
1234}
1235
1236static struct sort_dimension switch_sort_dimension = {
1237 .name = "switch",
1238 .cmp = switch_cmp,
1239};
1240
1241static int runtime_cmp(struct task_atoms *l, struct task_atoms *r)
1242{
1243 if (l->total_runtime < r->total_runtime)
1244 return -1;
1245 if (l->total_runtime > r->total_runtime)
1246 return 1;
1247
1248 return 0;
1249}
1250
1251static struct sort_dimension runtime_sort_dimension = {
1252 .name = "runtime",
1253 .cmp = runtime_cmp,
1254};
1255
1256static struct sort_dimension *available_sorts[] = {
1257 &pid_sort_dimension,
1258 &avg_sort_dimension,
1259 &max_sort_dimension,
1260 &switch_sort_dimension,
1261 &runtime_sort_dimension,
1262};
1263
1264#define NB_AVAILABLE_SORTS (int)(sizeof(available_sorts) / sizeof(struct sort_dimension *))
1265
1266static LIST_HEAD(sort_list);
1267
1268static int sort_dimension__add(char *tok, struct list_head *list)
1269{
1270 int i;
1271
1272 for (i = 0; i < NB_AVAILABLE_SORTS; i++) {
1273 if (!strcmp(available_sorts[i]->name, tok)) {
1274 list_add_tail(&available_sorts[i]->list, list);
1275
1276 return 0;
1277 }
1278 }
1279
1280 return -1;
1281}
1282
1283static void setup_sorting(void);
1284
1285static void sort_lat(void)
1286{
1287 struct rb_node *node;
1288
1289 for (;;) {
1290 struct task_atoms *data;
1291 node = rb_first(&lat_snapshot_root);
1292 if (!node)
1293 break;
1294
1295 rb_erase(node, &lat_snapshot_root);
1296 data = rb_entry(node, struct task_atoms, node);
1297 __thread_latency_insert(&sorted_lat_snapshot_root, data, &sort_list);
1298 }
1299}
1300
1137static void __cmd_lat(void) 1301static void __cmd_lat(void)
1138{ 1302{
1139 struct rb_node *next; 1303 struct rb_node *next;
1140 1304
1141 setup_pager(); 1305 setup_pager();
1142 read_events(); 1306 read_events();
1307 sort_lat();
1143 1308
1144 printf("-----------------------------------------------------------------------------------\n"); 1309 printf("-----------------------------------------------------------------------------------\n");
1145 printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms |\n"); 1310 printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms |\n");
1146 printf("-----------------------------------------------------------------------------------\n"); 1311 printf("-----------------------------------------------------------------------------------\n");
1147 1312
1148 next = rb_first(&lat_snapshot_root); 1313 next = rb_first(&sorted_lat_snapshot_root);
1149 1314
1150 while (next) { 1315 while (next) {
1151 struct task_atoms *atom_list; 1316 struct task_atoms *atom_list;
@@ -1469,11 +1634,30 @@ static const struct option options[] = {
1469 "replay sched behaviour from traces"), 1634 "replay sched behaviour from traces"),
1470 OPT_BOOLEAN('l', "latency", &lat_mode, 1635 OPT_BOOLEAN('l', "latency", &lat_mode,
1471 "measure various latencies"), 1636 "measure various latencies"),
1637 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1638 "sort by key(s): runtime, switch, avg, max"),
1472 OPT_BOOLEAN('v', "verbose", &verbose, 1639 OPT_BOOLEAN('v', "verbose", &verbose,
1473 "be more verbose (show symbol address, etc)"), 1640 "be more verbose (show symbol address, etc)"),
1474 OPT_END() 1641 OPT_END()
1475}; 1642};
1476 1643
1644static void setup_sorting(void)
1645{
1646 char *tmp, *tok, *str = strdup(sort_order);
1647
1648 for (tok = strtok_r(str, ", ", &tmp);
1649 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1650 if (sort_dimension__add(tok, &sort_list) < 0) {
1651 error("Unknown --sort key: `%s'", tok);
1652 usage_with_options(sched_usage, options);
1653 }
1654 }
1655
1656 free(str);
1657
1658 sort_dimension__add((char *)"pid", &cmp_pid);
1659}
1660
1477int cmd_sched(int argc, const char **argv, const char *prefix __used) 1661int cmd_sched(int argc, const char **argv, const char *prefix __used)
1478{ 1662{
1479 symbol__init(); 1663 symbol__init();
@@ -1496,6 +1680,8 @@ int cmd_sched(int argc, const char **argv, const char *prefix __used)
1496 else 1680 else
1497 usage_with_options(sched_usage, options); 1681 usage_with_options(sched_usage, options);
1498 1682
1683 setup_sorting();
1684
1499 if (replay_mode) 1685 if (replay_mode)
1500 __cmd_replay(); 1686 __cmd_replay();
1501 else if (lat_mode) 1687 else if (lat_mode)