1 /* 2 * Human Monitor Interface commands 3 * 4 * Copyright IBM, Corp. 2011 5 * 6 * Authors: 7 * Anthony Liguori <aliguori@us.ibm.com> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2. See 10 * the COPYING file in the top-level directory. 11 * 12 * Contributions after 2012-01-13 are licensed under the terms of the 13 * GNU GPL, version 2 or (at your option) any later version. 14 */ 15 16 #include "qemu/osdep.h" 17 #include "monitor/hmp.h" 18 #include "qemu/help_option.h" 19 #include "monitor/monitor.h" 20 #include "qapi/error.h" 21 #include "qapi/qapi-commands-control.h" 22 #include "qapi/qapi-commands-misc.h" 23 #include "qapi/qapi-commands-run-state.h" 24 #include "qapi/qapi-commands-stats.h" 25 #include "qapi/qmp/qdict.h" 26 #include "qapi/qmp/qerror.h" 27 #include "qemu/cutils.h" 28 #include "hw/core/cpu.h" 29 #include "hw/intc/intc.h" 30 31 bool hmp_handle_error(Monitor *mon, Error *err) 32 { 33 if (err) { 34 error_reportf_err(err, "Error: "); 35 return true; 36 } 37 return false; 38 } 39 40 /* 41 * Split @str at comma. 42 * A null @str defaults to "". 43 */ 44 strList *hmp_split_at_comma(const char *str) 45 { 46 char **split = g_strsplit(str ?: "", ",", -1); 47 strList *res = NULL; 48 strList **tail = &res; 49 int i; 50 51 for (i = 0; split[i]; i++) { 52 QAPI_LIST_APPEND(tail, split[i]); 53 } 54 55 g_free(split); 56 return res; 57 } 58 59 void hmp_info_name(Monitor *mon, const QDict *qdict) 60 { 61 NameInfo *info; 62 63 info = qmp_query_name(NULL); 64 if (info->name) { 65 monitor_printf(mon, "%s\n", info->name); 66 } 67 qapi_free_NameInfo(info); 68 } 69 70 void hmp_info_version(Monitor *mon, const QDict *qdict) 71 { 72 VersionInfo *info; 73 74 info = qmp_query_version(NULL); 75 76 monitor_printf(mon, "%" PRId64 ".%" PRId64 ".%" PRId64 "%s\n", 77 info->qemu->major, info->qemu->minor, info->qemu->micro, 78 info->package); 79 80 qapi_free_VersionInfo(info); 81 } 82 83 void hmp_info_status(Monitor *mon, const QDict *qdict) 84 { 85 StatusInfo *info; 86 87 info = qmp_query_status(NULL); 88 89 monitor_printf(mon, "VM status: %s%s", 90 info->running ? "running" : "paused", 91 info->singlestep ? " (single step mode)" : ""); 92 93 if (!info->running && info->status != RUN_STATE_PAUSED) { 94 monitor_printf(mon, " (%s)", RunState_str(info->status)); 95 } 96 97 monitor_printf(mon, "\n"); 98 99 qapi_free_StatusInfo(info); 100 } 101 102 static int hmp_info_pic_foreach(Object *obj, void *opaque) 103 { 104 InterruptStatsProvider *intc; 105 InterruptStatsProviderClass *k; 106 Monitor *mon = opaque; 107 108 if (object_dynamic_cast(obj, TYPE_INTERRUPT_STATS_PROVIDER)) { 109 intc = INTERRUPT_STATS_PROVIDER(obj); 110 k = INTERRUPT_STATS_PROVIDER_GET_CLASS(obj); 111 if (k->print_info) { 112 k->print_info(intc, mon); 113 } else { 114 monitor_printf(mon, "Interrupt controller information not available for %s.\n", 115 object_get_typename(obj)); 116 } 117 } 118 119 return 0; 120 } 121 122 void hmp_info_pic(Monitor *mon, const QDict *qdict) 123 { 124 object_child_foreach_recursive(object_get_root(), 125 hmp_info_pic_foreach, mon); 126 } 127 128 void hmp_quit(Monitor *mon, const QDict *qdict) 129 { 130 monitor_suspend(mon); 131 qmp_quit(NULL); 132 } 133 134 void hmp_stop(Monitor *mon, const QDict *qdict) 135 { 136 qmp_stop(NULL); 137 } 138 139 void hmp_sync_profile(Monitor *mon, const QDict *qdict) 140 { 141 const char *op = qdict_get_try_str(qdict, "op"); 142 143 if (op == NULL) { 144 bool on = qsp_is_enabled(); 145 146 monitor_printf(mon, "sync-profile is %s\n", on ? "on" : "off"); 147 return; 148 } 149 if (!strcmp(op, "on")) { 150 qsp_enable(); 151 } else if (!strcmp(op, "off")) { 152 qsp_disable(); 153 } else if (!strcmp(op, "reset")) { 154 qsp_reset(); 155 } else { 156 Error *err = NULL; 157 158 error_setg(&err, QERR_INVALID_PARAMETER, op); 159 hmp_handle_error(mon, err); 160 } 161 } 162 163 void hmp_exit_preconfig(Monitor *mon, const QDict *qdict) 164 { 165 Error *err = NULL; 166 167 qmp_x_exit_preconfig(&err); 168 hmp_handle_error(mon, err); 169 } 170 171 void hmp_cpu(Monitor *mon, const QDict *qdict) 172 { 173 int64_t cpu_index; 174 175 /* XXX: drop the monitor_set_cpu() usage when all HMP commands that 176 use it are converted to the QAPI */ 177 cpu_index = qdict_get_int(qdict, "index"); 178 if (monitor_set_cpu(mon, cpu_index) < 0) { 179 monitor_printf(mon, "invalid CPU index\n"); 180 } 181 } 182 183 void hmp_cont(Monitor *mon, const QDict *qdict) 184 { 185 Error *err = NULL; 186 187 qmp_cont(&err); 188 hmp_handle_error(mon, err); 189 } 190 191 void hmp_change(Monitor *mon, const QDict *qdict) 192 { 193 const char *device = qdict_get_str(qdict, "device"); 194 const char *target = qdict_get_str(qdict, "target"); 195 const char *arg = qdict_get_try_str(qdict, "arg"); 196 const char *read_only = qdict_get_try_str(qdict, "read-only-mode"); 197 bool force = qdict_get_try_bool(qdict, "force", false); 198 Error *err = NULL; 199 200 #ifdef CONFIG_VNC 201 if (strcmp(device, "vnc") == 0) { 202 hmp_change_vnc(mon, device, target, arg, read_only, force, &err); 203 } else 204 #endif 205 { 206 hmp_change_medium(mon, device, target, arg, read_only, force, &err); 207 } 208 209 hmp_handle_error(mon, err); 210 } 211 212 void hmp_getfd(Monitor *mon, const QDict *qdict) 213 { 214 const char *fdname = qdict_get_str(qdict, "fdname"); 215 Error *err = NULL; 216 217 qmp_getfd(fdname, &err); 218 hmp_handle_error(mon, err); 219 } 220 221 void hmp_closefd(Monitor *mon, const QDict *qdict) 222 { 223 const char *fdname = qdict_get_str(qdict, "fdname"); 224 Error *err = NULL; 225 226 qmp_closefd(fdname, &err); 227 hmp_handle_error(mon, err); 228 } 229 230 void hmp_info_iothreads(Monitor *mon, const QDict *qdict) 231 { 232 IOThreadInfoList *info_list = qmp_query_iothreads(NULL); 233 IOThreadInfoList *info; 234 IOThreadInfo *value; 235 236 for (info = info_list; info; info = info->next) { 237 value = info->value; 238 monitor_printf(mon, "%s:\n", value->id); 239 monitor_printf(mon, " thread_id=%" PRId64 "\n", value->thread_id); 240 monitor_printf(mon, " poll-max-ns=%" PRId64 "\n", value->poll_max_ns); 241 monitor_printf(mon, " poll-grow=%" PRId64 "\n", value->poll_grow); 242 monitor_printf(mon, " poll-shrink=%" PRId64 "\n", value->poll_shrink); 243 monitor_printf(mon, " aio-max-batch=%" PRId64 "\n", 244 value->aio_max_batch); 245 } 246 247 qapi_free_IOThreadInfoList(info_list); 248 } 249 250 static void print_stats_schema_value(Monitor *mon, StatsSchemaValue *value) 251 { 252 const char *unit = NULL; 253 monitor_printf(mon, " %s (%s%s", value->name, StatsType_str(value->type), 254 value->has_unit || value->exponent ? ", " : ""); 255 256 if (value->has_unit) { 257 if (value->unit == STATS_UNIT_SECONDS) { 258 unit = "s"; 259 } else if (value->unit == STATS_UNIT_BYTES) { 260 unit = "B"; 261 } 262 } 263 264 if (unit && value->base == 10 && 265 value->exponent >= -18 && value->exponent <= 18 && 266 value->exponent % 3 == 0) { 267 monitor_puts(mon, si_prefix(value->exponent)); 268 } else if (unit && value->base == 2 && 269 value->exponent >= 0 && value->exponent <= 60 && 270 value->exponent % 10 == 0) { 271 272 monitor_puts(mon, iec_binary_prefix(value->exponent)); 273 } else if (value->exponent) { 274 /* Use exponential notation and write the unit's English name */ 275 monitor_printf(mon, "* %d^%d%s", 276 value->base, value->exponent, 277 value->has_unit ? " " : ""); 278 unit = NULL; 279 } 280 281 if (value->has_unit) { 282 monitor_puts(mon, unit ? unit : StatsUnit_str(value->unit)); 283 } 284 285 /* Print bucket size for linear histograms */ 286 if (value->type == STATS_TYPE_LINEAR_HISTOGRAM && value->has_bucket_size) { 287 monitor_printf(mon, ", bucket size=%d", value->bucket_size); 288 } 289 monitor_printf(mon, ")"); 290 } 291 292 static StatsSchemaValueList *find_schema_value_list( 293 StatsSchemaList *list, StatsProvider provider, 294 StatsTarget target) 295 { 296 StatsSchemaList *node; 297 298 for (node = list; node; node = node->next) { 299 if (node->value->provider == provider && 300 node->value->target == target) { 301 return node->value->stats; 302 } 303 } 304 return NULL; 305 } 306 307 static void print_stats_results(Monitor *mon, StatsTarget target, 308 bool show_provider, 309 StatsResult *result, 310 StatsSchemaList *schema) 311 { 312 /* Find provider schema */ 313 StatsSchemaValueList *schema_value_list = 314 find_schema_value_list(schema, result->provider, target); 315 StatsList *stats_list; 316 317 if (!schema_value_list) { 318 monitor_printf(mon, "failed to find schema list for %s\n", 319 StatsProvider_str(result->provider)); 320 return; 321 } 322 323 if (show_provider) { 324 monitor_printf(mon, "provider: %s\n", 325 StatsProvider_str(result->provider)); 326 } 327 328 for (stats_list = result->stats; stats_list; 329 stats_list = stats_list->next, 330 schema_value_list = schema_value_list->next) { 331 332 Stats *stats = stats_list->value; 333 StatsValue *stats_value = stats->value; 334 StatsSchemaValue *schema_value = schema_value_list->value; 335 336 /* Find schema entry */ 337 while (!g_str_equal(stats->name, schema_value->name)) { 338 if (!schema_value_list->next) { 339 monitor_printf(mon, "failed to find schema entry for %s\n", 340 stats->name); 341 return; 342 } 343 schema_value_list = schema_value_list->next; 344 schema_value = schema_value_list->value; 345 } 346 347 print_stats_schema_value(mon, schema_value); 348 349 if (stats_value->type == QTYPE_QNUM) { 350 monitor_printf(mon, ": %" PRId64 "\n", stats_value->u.scalar); 351 } else if (stats_value->type == QTYPE_QBOOL) { 352 monitor_printf(mon, ": %s\n", stats_value->u.boolean ? "yes" : "no"); 353 } else if (stats_value->type == QTYPE_QLIST) { 354 uint64List *list; 355 int i; 356 357 monitor_printf(mon, ": "); 358 for (list = stats_value->u.list, i = 1; 359 list; 360 list = list->next, i++) { 361 monitor_printf(mon, "[%d]=%" PRId64 " ", i, list->value); 362 } 363 monitor_printf(mon, "\n"); 364 } 365 } 366 } 367 368 /* Create the StatsFilter that is needed for an "info stats" invocation. */ 369 static StatsFilter *stats_filter(StatsTarget target, const char *names, 370 int cpu_index, StatsProvider provider) 371 { 372 StatsFilter *filter = g_malloc0(sizeof(*filter)); 373 StatsProvider provider_idx; 374 StatsRequestList *request_list = NULL; 375 376 filter->target = target; 377 switch (target) { 378 case STATS_TARGET_VM: 379 break; 380 case STATS_TARGET_VCPU: 381 { 382 strList *vcpu_list = NULL; 383 CPUState *cpu = qemu_get_cpu(cpu_index); 384 char *canonical_path = object_get_canonical_path(OBJECT(cpu)); 385 386 QAPI_LIST_PREPEND(vcpu_list, canonical_path); 387 filter->u.vcpu.has_vcpus = true; 388 filter->u.vcpu.vcpus = vcpu_list; 389 break; 390 } 391 default: 392 break; 393 } 394 395 if (!names && provider == STATS_PROVIDER__MAX) { 396 return filter; 397 } 398 399 /* 400 * "info stats" can only query either one or all the providers. Querying 401 * by name, but not by provider, requires the creation of one filter per 402 * provider. 403 */ 404 for (provider_idx = 0; provider_idx < STATS_PROVIDER__MAX; provider_idx++) { 405 if (provider == STATS_PROVIDER__MAX || provider == provider_idx) { 406 StatsRequest *request = g_new0(StatsRequest, 1); 407 request->provider = provider_idx; 408 if (names && !g_str_equal(names, "*")) { 409 request->has_names = true; 410 request->names = hmp_split_at_comma(names); 411 } 412 QAPI_LIST_PREPEND(request_list, request); 413 } 414 } 415 416 filter->has_providers = true; 417 filter->providers = request_list; 418 return filter; 419 } 420 421 void hmp_info_stats(Monitor *mon, const QDict *qdict) 422 { 423 const char *target_str = qdict_get_str(qdict, "target"); 424 const char *provider_str = qdict_get_try_str(qdict, "provider"); 425 const char *names = qdict_get_try_str(qdict, "names"); 426 427 StatsProvider provider = STATS_PROVIDER__MAX; 428 StatsTarget target; 429 Error *err = NULL; 430 g_autoptr(StatsSchemaList) schema = NULL; 431 g_autoptr(StatsResultList) stats = NULL; 432 g_autoptr(StatsFilter) filter = NULL; 433 StatsResultList *entry; 434 435 target = qapi_enum_parse(&StatsTarget_lookup, target_str, -1, &err); 436 if (err) { 437 monitor_printf(mon, "invalid stats target %s\n", target_str); 438 goto exit_no_print; 439 } 440 if (provider_str) { 441 provider = qapi_enum_parse(&StatsProvider_lookup, provider_str, -1, &err); 442 if (err) { 443 monitor_printf(mon, "invalid stats provider %s\n", provider_str); 444 goto exit_no_print; 445 } 446 } 447 448 schema = qmp_query_stats_schemas(provider_str ? true : false, 449 provider, &err); 450 if (err) { 451 goto exit; 452 } 453 454 switch (target) { 455 case STATS_TARGET_VM: 456 filter = stats_filter(target, names, -1, provider); 457 break; 458 case STATS_TARGET_VCPU: {} 459 int cpu_index = monitor_get_cpu_index(mon); 460 filter = stats_filter(target, names, cpu_index, provider); 461 break; 462 default: 463 abort(); 464 } 465 466 stats = qmp_query_stats(filter, &err); 467 if (err) { 468 goto exit; 469 } 470 for (entry = stats; entry; entry = entry->next) { 471 print_stats_results(mon, target, provider_str == NULL, entry->value, schema); 472 } 473 474 exit: 475 if (err) { 476 monitor_printf(mon, "%s\n", error_get_pretty(err)); 477 } 478 exit_no_print: 479 error_free(err); 480 } 481