[18b5402c] | 1 | /*
|
---|
| 2 | * Copyright (c) 2010 Stanislav Kozina
|
---|
[e1b6742] | 3 | * Copyright (c) 2010 Martin Decky
|
---|
[18b5402c] | 4 | * All rights reserved.
|
---|
| 5 | *
|
---|
| 6 | * Redistribution and use in source and binary forms, with or without
|
---|
| 7 | * modification, are permitted provided that the following conditions
|
---|
| 8 | * are met:
|
---|
| 9 | *
|
---|
| 10 | * - Redistributions of source code must retain the above copyright
|
---|
| 11 | * notice, this list of conditions and the following disclaimer.
|
---|
| 12 | * - Redistributions in binary form must reproduce the above copyright
|
---|
| 13 | * notice, this list of conditions and the following disclaimer in the
|
---|
| 14 | * documentation and/or other materials provided with the distribution.
|
---|
| 15 | * - The name of the author may not be used to endorse or promote products
|
---|
| 16 | * derived from this software without specific prior written permission.
|
---|
| 17 | *
|
---|
| 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
---|
| 19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
---|
| 20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
---|
| 21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
---|
| 22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
---|
| 23 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
---|
| 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
---|
| 25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
---|
| 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
---|
| 27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
---|
| 28 | */
|
---|
| 29 |
|
---|
[da98918] | 30 | /** @addtogroup tasks
|
---|
[18b5402c] | 31 | * @brief Task lister.
|
---|
| 32 | * @{
|
---|
| 33 | */
|
---|
| 34 | /**
|
---|
| 35 | * @file
|
---|
| 36 | */
|
---|
| 37 |
|
---|
| 38 | #include <stdio.h>
|
---|
| 39 | #include <task.h>
|
---|
| 40 | #include <thread.h>
|
---|
[9dae191e] | 41 | #include <stats.h>
|
---|
[18b5402c] | 42 | #include <errno.h>
|
---|
| 43 | #include <stdlib.h>
|
---|
| 44 | #include <malloc.h>
|
---|
[9dae191e] | 45 | #include <inttypes.h>
|
---|
[e1b6742] | 46 | #include <bool.h>
|
---|
[e535eeb] | 47 | #include <str.h>
|
---|
[9dae191e] | 48 | #include <arg_parse.h>
|
---|
[ea55bc4] | 49 |
|
---|
[da98918] | 50 | #define NAME "tasks"
|
---|
[9dae191e] | 51 |
|
---|
| 52 | #define TASK_COUNT 10
|
---|
| 53 | #define THREAD_COUNT 50
|
---|
[18b5402c] | 54 |
|
---|
[9dae191e] | 55 | #define PRINT_LOAD1(x) ((x) >> 11)
|
---|
| 56 | #define PRINT_LOAD2(x) (((x) & 0x7ff) / 2)
|
---|
[9d491a7] | 57 |
|
---|
[18b5402c] | 58 | static void list_tasks(void)
|
---|
| 59 | {
|
---|
[9dae191e] | 60 | size_t count;
|
---|
[dec16a2] | 61 | stats_task_t *stats_tasks = stats_get_tasks(&count);
|
---|
[9dae191e] | 62 |
|
---|
[dec16a2] | 63 | if (stats_tasks == NULL) {
|
---|
[9dae191e] | 64 | fprintf(stderr, "%s: Unable to get tasks\n", NAME);
|
---|
| 65 | return;
|
---|
[18b5402c] | 66 | }
|
---|
[9dae191e] | 67 |
|
---|
| 68 | printf(" ID Threads Mem uCycles kCycles Name\n");
|
---|
| 69 |
|
---|
| 70 | size_t i;
|
---|
| 71 | for (i = 0; i < count; i++) {
|
---|
[dec16a2] | 72 | uint64_t virtmem, ucycles, kcycles;
|
---|
| 73 | char vmsuffix, usuffix, ksuffix;
|
---|
| 74 |
|
---|
| 75 | order_suffix(stats_tasks[i].virtmem, &virtmem, &vmsuffix);
|
---|
| 76 | order_suffix(stats_tasks[i].ucycles, &ucycles, &usuffix);
|
---|
| 77 | order_suffix(stats_tasks[i].kcycles, &kcycles, &ksuffix);
|
---|
| 78 |
|
---|
| 79 | printf("%8" PRIu64 "%8u %8" PRIu64"%c %12"
|
---|
| 80 | PRIu64 "%c %12" PRIu64 "%c %s\n", stats_tasks[i].task_id,
|
---|
| 81 | stats_tasks[i].threads, virtmem, vmsuffix, ucycles, usuffix,
|
---|
| 82 | kcycles, ksuffix, stats_tasks[i].name);
|
---|
[18b5402c] | 83 | }
|
---|
[9dae191e] | 84 |
|
---|
[dec16a2] | 85 | free(stats_tasks);
|
---|
[18b5402c] | 86 | }
|
---|
| 87 |
|
---|
[e1b6742] | 88 | static void list_threads(task_id_t task_id, bool all)
|
---|
[18b5402c] | 89 | {
|
---|
[e1b6742] | 90 | size_t count;
|
---|
[dec16a2] | 91 | stats_thread_t *stats_threads = stats_get_threads(&count);
|
---|
[e1b6742] | 92 |
|
---|
[dec16a2] | 93 | if (stats_threads == NULL) {
|
---|
[e1b6742] | 94 | fprintf(stderr, "%s: Unable to get threads\n", NAME);
|
---|
| 95 | return;
|
---|
[34bba0e] | 96 | }
|
---|
[e1b6742] | 97 |
|
---|
[ea55bc4] | 98 | printf(" ID State CPU Prio [k]uCycles [k]kcycles Cycle fault\n");
|
---|
[e1b6742] | 99 | size_t i;
|
---|
| 100 | for (i = 0; i < count; i++) {
|
---|
[dec16a2] | 101 | if ((all) || (stats_threads[i].task_id == task_id)) {
|
---|
| 102 | uint64_t ucycles, kcycles;
|
---|
| 103 | char usuffix, ksuffix;
|
---|
[e1b6742] | 104 |
|
---|
[dec16a2] | 105 | order_suffix(stats_threads[i].ucycles, &ucycles, &usuffix);
|
---|
| 106 | order_suffix(stats_threads[i].kcycles, &kcycles, &ksuffix);
|
---|
| 107 |
|
---|
| 108 | if (stats_threads[i].on_cpu) {
|
---|
| 109 | printf("%8" PRIu64 " %-8s %4u %6d %12"
|
---|
| 110 | PRIu64"%c %12" PRIu64"%c\n", stats_threads[i].thread_id,
|
---|
| 111 | thread_get_state(stats_threads[i].state),
|
---|
| 112 | stats_threads[i].cpu, stats_threads[i].priority,
|
---|
| 113 | ucycles, usuffix, kcycles, ksuffix);
|
---|
| 114 | } else {
|
---|
| 115 | printf("%8" PRIu64 " %-8s ---- %6d %12"
|
---|
| 116 | PRIu64"%c %12" PRIu64"%c\n", stats_threads[i].thread_id,
|
---|
| 117 | thread_get_state(stats_threads[i].state),
|
---|
| 118 | stats_threads[i].priority,
|
---|
| 119 | ucycles, usuffix, kcycles, ksuffix);
|
---|
| 120 | }
|
---|
| 121 | }
|
---|
[18b5402c] | 122 | }
|
---|
[e1b6742] | 123 |
|
---|
[dec16a2] | 124 | free(stats_threads);
|
---|
[18b5402c] | 125 | }
|
---|
| 126 |
|
---|
[9dae191e] | 127 | static void print_load(void)
|
---|
[944f2cab] | 128 | {
|
---|
[9dae191e] | 129 | size_t count;
|
---|
[c3d4bb45] | 130 | load_t *load = stats_get_load(&count);
|
---|
[9dae191e] | 131 |
|
---|
| 132 | if (load == NULL) {
|
---|
| 133 | fprintf(stderr, "%s: Unable to get load\n", NAME);
|
---|
| 134 | return;
|
---|
| 135 | }
|
---|
| 136 |
|
---|
[80badbe] | 137 | printf("%s: Load average: ", NAME);
|
---|
[9dae191e] | 138 |
|
---|
| 139 | size_t i;
|
---|
| 140 | for (i = 0; i < count; i++) {
|
---|
| 141 | if (i > 0)
|
---|
| 142 | printf(" ");
|
---|
| 143 |
|
---|
[c3d4bb45] | 144 | stats_print_load_fragment(load[i], 2);
|
---|
[9dae191e] | 145 | }
|
---|
| 146 |
|
---|
| 147 | printf("\n");
|
---|
| 148 |
|
---|
| 149 | free(load);
|
---|
[944f2cab] | 150 | }
|
---|
| 151 |
|
---|
[9dae191e] | 152 | static void list_cpus(void)
|
---|
[62550dce] | 153 | {
|
---|
[9dae191e] | 154 | size_t count;
|
---|
[c3d4bb45] | 155 | stats_cpu_t *cpus = stats_get_cpus(&count);
|
---|
[9dae191e] | 156 |
|
---|
| 157 | if (cpus == NULL) {
|
---|
| 158 | fprintf(stderr, "%s: Unable to get CPU statistics\n", NAME);
|
---|
| 159 | return;
|
---|
| 160 | }
|
---|
| 161 |
|
---|
| 162 | printf("%s: %u CPU(s) detected\n", NAME, count);
|
---|
| 163 |
|
---|
[62550dce] | 164 | size_t i;
|
---|
[9dae191e] | 165 | for (i = 0; i < count; i++) {
|
---|
[bd01a4e] | 166 | if (cpus[i].active) {
|
---|
| 167 | printf("cpu%u: %" PRIu16 " MHz, busy ticks: "
|
---|
| 168 | "%" PRIu64 ", idle ticks: %" PRIu64 "\n",
|
---|
| 169 | cpus[i].id, cpus[i].frequency_mhz, cpus[i].busy_ticks,
|
---|
| 170 | cpus[i].idle_ticks);
|
---|
| 171 | } else {
|
---|
| 172 | printf("cpu%u: inactive\n", cpus[i].id);
|
---|
| 173 | }
|
---|
[62550dce] | 174 | }
|
---|
[9dae191e] | 175 |
|
---|
| 176 | free(cpus);
|
---|
[62550dce] | 177 | }
|
---|
| 178 |
|
---|
[34bba0e] | 179 | static void usage()
|
---|
| 180 | {
|
---|
[9dae191e] | 181 | printf(
|
---|
[e1b6742] | 182 | "Usage: tasks [-t task_id] [-a] [-l] [-c]\n" \
|
---|
[9dae191e] | 183 | "\n" \
|
---|
| 184 | "Options:\n" \
|
---|
| 185 | "\t-t task_id\n" \
|
---|
| 186 | "\t--task=task_id\n" \
|
---|
| 187 | "\t\tList threads of the given task\n" \
|
---|
| 188 | "\n" \
|
---|
[e1b6742] | 189 | "\t-a\n" \
|
---|
| 190 | "\t--all\n" \
|
---|
| 191 | "\t\tList all threads\n" \
|
---|
| 192 | "\n" \
|
---|
[9dae191e] | 193 | "\t-l\n" \
|
---|
| 194 | "\t--load\n" \
|
---|
| 195 | "\t\tPrint system load\n" \
|
---|
| 196 | "\n" \
|
---|
| 197 | "\t-c\n" \
|
---|
| 198 | "\t--cpu\n" \
|
---|
| 199 | "\t\tList CPUs\n" \
|
---|
| 200 | "\n" \
|
---|
| 201 | "\t-h\n" \
|
---|
| 202 | "\t--help\n" \
|
---|
| 203 | "\t\tPrint this usage information\n"
|
---|
| 204 | "\n" \
|
---|
| 205 | "Without any options all tasks are listed\n"
|
---|
| 206 | );
|
---|
[34bba0e] | 207 | }
|
---|
| 208 |
|
---|
[18b5402c] | 209 | int main(int argc, char *argv[])
|
---|
| 210 | {
|
---|
[9dae191e] | 211 | bool toggle_tasks = true;
|
---|
| 212 | bool toggle_threads = false;
|
---|
[e1b6742] | 213 | bool toggle_all = false;
|
---|
[9dae191e] | 214 | bool toggle_load = false;
|
---|
| 215 | bool toggle_cpus = false;
|
---|
| 216 |
|
---|
[e1b6742] | 217 | task_id_t task_id = 0;
|
---|
[9dae191e] | 218 |
|
---|
| 219 | int i;
|
---|
| 220 | for (i = 1; i < argc; i++) {
|
---|
| 221 | int off;
|
---|
| 222 |
|
---|
| 223 | /* Usage */
|
---|
| 224 | if ((off = arg_parse_short_long(argv[i], "-h", "--help")) != -1) {
|
---|
[34bba0e] | 225 | usage();
|
---|
[9dae191e] | 226 | return 0;
|
---|
| 227 | }
|
---|
| 228 |
|
---|
[e1b6742] | 229 | /* All threads */
|
---|
| 230 | if ((off = arg_parse_short_long(argv[i], "-a", "--all")) != -1) {
|
---|
| 231 | toggle_tasks = false;
|
---|
| 232 | toggle_threads = true;
|
---|
| 233 | toggle_all = true;
|
---|
| 234 | continue;
|
---|
| 235 | }
|
---|
| 236 |
|
---|
[9dae191e] | 237 | /* Load */
|
---|
| 238 | if ((off = arg_parse_short_long(argv[i], "-l", "--load")) != -1) {
|
---|
| 239 | toggle_tasks = false;
|
---|
| 240 | toggle_load = true;
|
---|
| 241 | continue;
|
---|
| 242 | }
|
---|
| 243 |
|
---|
| 244 | /* CPUs */
|
---|
| 245 | if ((off = arg_parse_short_long(argv[i], "-c", "--cpus")) != -1) {
|
---|
| 246 | toggle_tasks = false;
|
---|
| 247 | toggle_cpus = true;
|
---|
| 248 | continue;
|
---|
| 249 | }
|
---|
| 250 |
|
---|
| 251 | /* Threads */
|
---|
| 252 | if ((off = arg_parse_short_long(argv[i], "-t", "--task=")) != -1) {
|
---|
| 253 | // TODO: Support for 64b range
|
---|
| 254 | int tmp;
|
---|
| 255 | int ret = arg_parse_int(argc, argv, &i, &tmp, off);
|
---|
| 256 | if (ret != EOK) {
|
---|
| 257 | printf("%s: Malformed task_id '%s'\n", NAME, argv[i]);
|
---|
| 258 | return -1;
|
---|
| 259 | }
|
---|
| 260 |
|
---|
| 261 | task_id = tmp;
|
---|
| 262 |
|
---|
| 263 | toggle_tasks = false;
|
---|
| 264 | toggle_threads = true;
|
---|
| 265 | continue;
|
---|
[18b5402c] | 266 | }
|
---|
| 267 | }
|
---|
[9dae191e] | 268 |
|
---|
| 269 | if (toggle_tasks)
|
---|
| 270 | list_tasks();
|
---|
| 271 |
|
---|
| 272 | if (toggle_threads)
|
---|
[e1b6742] | 273 | list_threads(task_id, toggle_all);
|
---|
[9dae191e] | 274 |
|
---|
| 275 | if (toggle_load)
|
---|
| 276 | print_load();
|
---|
| 277 |
|
---|
| 278 | if (toggle_cpus)
|
---|
| 279 | list_cpus();
|
---|
| 280 |
|
---|
[18b5402c] | 281 | return 0;
|
---|
| 282 | }
|
---|
| 283 |
|
---|
| 284 | /** @}
|
---|
| 285 | */
|
---|