builtin-kvm.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976
  1. #include "builtin.h"
  2. #include "perf.h"
  3. #include "util/evsel.h"
  4. #include "util/util.h"
  5. #include "util/cache.h"
  6. #include "util/symbol.h"
  7. #include "util/thread.h"
  8. #include "util/header.h"
  9. #include "util/session.h"
  10. #include "util/parse-options.h"
  11. #include "util/trace-event.h"
  12. #include "util/debug.h"
  13. #include "util/debugfs.h"
  14. #include "util/tool.h"
  15. #include "util/stat.h"
  16. #include <sys/prctl.h>
  17. #include <semaphore.h>
  18. #include <pthread.h>
  19. #include <math.h>
  20. #include "../../arch/x86/include/asm/svm.h"
  21. #include "../../arch/x86/include/asm/vmx.h"
  22. #include "../../arch/x86/include/asm/kvm.h"
  23. struct event_key {
  24. #define INVALID_KEY (~0ULL)
  25. u64 key;
  26. int info;
  27. };
  28. struct kvm_events_ops {
  29. bool (*is_begin_event)(struct event_format *event, void *data,
  30. struct event_key *key);
  31. bool (*is_end_event)(struct event_format *event, void *data,
  32. struct event_key *key);
  33. void (*decode_key)(struct event_key *key, char decode[20]);
  34. const char *name;
  35. };
  36. static void exit_event_get_key(struct event_format *event, void *data,
  37. struct event_key *key)
  38. {
  39. key->info = 0;
  40. key->key = raw_field_value(event, "exit_reason", data);
  41. }
  42. static bool kvm_exit_event(struct event_format *event)
  43. {
  44. return !strcmp(event->name, "kvm_exit");
  45. }
  46. static bool exit_event_begin(struct event_format *event, void *data,
  47. struct event_key *key)
  48. {
  49. if (kvm_exit_event(event)) {
  50. exit_event_get_key(event, data, key);
  51. return true;
  52. }
  53. return false;
  54. }
  55. static bool kvm_entry_event(struct event_format *event)
  56. {
  57. return !strcmp(event->name, "kvm_entry");
  58. }
  59. static bool exit_event_end(struct event_format *event, void *data __maybe_unused,
  60. struct event_key *key __maybe_unused)
  61. {
  62. return kvm_entry_event(event);
  63. }
  64. struct exit_reasons_table {
  65. unsigned long exit_code;
  66. const char *reason;
  67. };
  68. struct exit_reasons_table vmx_exit_reasons[] = {
  69. VMX_EXIT_REASONS
  70. };
  71. struct exit_reasons_table svm_exit_reasons[] = {
  72. SVM_EXIT_REASONS
  73. };
  74. static int cpu_isa;
  75. static const char *get_exit_reason(u64 exit_code)
  76. {
  77. int table_size = ARRAY_SIZE(svm_exit_reasons);
  78. struct exit_reasons_table *table = svm_exit_reasons;
  79. if (cpu_isa == 1) {
  80. table = vmx_exit_reasons;
  81. table_size = ARRAY_SIZE(vmx_exit_reasons);
  82. }
  83. while (table_size--) {
  84. if (table->exit_code == exit_code)
  85. return table->reason;
  86. table++;
  87. }
  88. pr_err("unknown kvm exit code:%lld on %s\n",
  89. (unsigned long long)exit_code, cpu_isa ? "VMX" : "SVM");
  90. return "UNKNOWN";
  91. }
  92. static void exit_event_decode_key(struct event_key *key, char decode[20])
  93. {
  94. const char *exit_reason = get_exit_reason(key->key);
  95. scnprintf(decode, 20, "%s", exit_reason);
  96. }
  97. static struct kvm_events_ops exit_events = {
  98. .is_begin_event = exit_event_begin,
  99. .is_end_event = exit_event_end,
  100. .decode_key = exit_event_decode_key,
  101. .name = "VM-EXIT"
  102. };
  103. /*
  104. * For the mmio events, we treat:
  105. * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry
  106. * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...).
  107. */
  108. static void mmio_event_get_key(struct event_format *event, void *data,
  109. struct event_key *key)
  110. {
  111. key->key = raw_field_value(event, "gpa", data);
  112. key->info = raw_field_value(event, "type", data);
  113. }
  114. #define KVM_TRACE_MMIO_READ_UNSATISFIED 0
  115. #define KVM_TRACE_MMIO_READ 1
  116. #define KVM_TRACE_MMIO_WRITE 2
  117. static bool mmio_event_begin(struct event_format *event, void *data,
  118. struct event_key *key)
  119. {
  120. /* MMIO read begin event in kernel. */
  121. if (kvm_exit_event(event))
  122. return true;
  123. /* MMIO write begin event in kernel. */
  124. if (!strcmp(event->name, "kvm_mmio") &&
  125. raw_field_value(event, "type", data) == KVM_TRACE_MMIO_WRITE) {
  126. mmio_event_get_key(event, data, key);
  127. return true;
  128. }
  129. return false;
  130. }
  131. static bool mmio_event_end(struct event_format *event, void *data,
  132. struct event_key *key)
  133. {
  134. /* MMIO write end event in kernel. */
  135. if (kvm_entry_event(event))
  136. return true;
  137. /* MMIO read end event in kernel.*/
  138. if (!strcmp(event->name, "kvm_mmio") &&
  139. raw_field_value(event, "type", data) == KVM_TRACE_MMIO_READ) {
  140. mmio_event_get_key(event, data, key);
  141. return true;
  142. }
  143. return false;
  144. }
  145. static void mmio_event_decode_key(struct event_key *key, char decode[20])
  146. {
  147. scnprintf(decode, 20, "%#lx:%s", (unsigned long)key->key,
  148. key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R");
  149. }
  150. static struct kvm_events_ops mmio_events = {
  151. .is_begin_event = mmio_event_begin,
  152. .is_end_event = mmio_event_end,
  153. .decode_key = mmio_event_decode_key,
  154. .name = "MMIO Access"
  155. };
  156. /* The time of emulation pio access is from kvm_pio to kvm_entry. */
  157. static void ioport_event_get_key(struct event_format *event, void *data,
  158. struct event_key *key)
  159. {
  160. key->key = raw_field_value(event, "port", data);
  161. key->info = raw_field_value(event, "rw", data);
  162. }
  163. static bool ioport_event_begin(struct event_format *event, void *data,
  164. struct event_key *key)
  165. {
  166. if (!strcmp(event->name, "kvm_pio")) {
  167. ioport_event_get_key(event, data, key);
  168. return true;
  169. }
  170. return false;
  171. }
  172. static bool ioport_event_end(struct event_format *event, void *data __maybe_unused,
  173. struct event_key *key __maybe_unused)
  174. {
  175. if (kvm_entry_event(event))
  176. return true;
  177. return false;
  178. }
  179. static void ioport_event_decode_key(struct event_key *key, char decode[20])
  180. {
  181. scnprintf(decode, 20, "%#llx:%s", (unsigned long long)key->key,
  182. key->info ? "POUT" : "PIN");
  183. }
  184. static struct kvm_events_ops ioport_events = {
  185. .is_begin_event = ioport_event_begin,
  186. .is_end_event = ioport_event_end,
  187. .decode_key = ioport_event_decode_key,
  188. .name = "IO Port Access"
  189. };
  190. static const char *report_event = "vmexit";
  191. struct kvm_events_ops *events_ops;
  192. static bool register_kvm_events_ops(void)
  193. {
  194. bool ret = true;
  195. if (!strcmp(report_event, "vmexit"))
  196. events_ops = &exit_events;
  197. else if (!strcmp(report_event, "mmio"))
  198. events_ops = &mmio_events;
  199. else if (!strcmp(report_event, "ioport"))
  200. events_ops = &ioport_events;
  201. else {
  202. pr_err("Unknown report event:%s\n", report_event);
  203. ret = false;
  204. }
  205. return ret;
  206. }
  207. struct kvm_event_stats {
  208. u64 time;
  209. struct stats stats;
  210. };
  211. struct kvm_event {
  212. struct list_head hash_entry;
  213. struct rb_node rb;
  214. struct event_key key;
  215. struct kvm_event_stats total;
  216. #define DEFAULT_VCPU_NUM 8
  217. int max_vcpu;
  218. struct kvm_event_stats *vcpu;
  219. };
  220. struct vcpu_event_record {
  221. int vcpu_id;
  222. u64 start_time;
  223. struct kvm_event *last_event;
  224. };
  225. #define EVENTS_BITS 12
  226. #define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS)
  227. static u64 total_time;
  228. static u64 total_count;
  229. static struct list_head kvm_events_cache[EVENTS_CACHE_SIZE];
  230. static void init_kvm_event_record(void)
  231. {
  232. int i;
  233. for (i = 0; i < (int)EVENTS_CACHE_SIZE; i++)
  234. INIT_LIST_HEAD(&kvm_events_cache[i]);
  235. }
  236. static int kvm_events_hash_fn(u64 key)
  237. {
  238. return key & (EVENTS_CACHE_SIZE - 1);
  239. }
  240. static bool kvm_event_expand(struct kvm_event *event, int vcpu_id)
  241. {
  242. int old_max_vcpu = event->max_vcpu;
  243. if (vcpu_id < event->max_vcpu)
  244. return true;
  245. while (event->max_vcpu <= vcpu_id)
  246. event->max_vcpu += DEFAULT_VCPU_NUM;
  247. event->vcpu = realloc(event->vcpu,
  248. event->max_vcpu * sizeof(*event->vcpu));
  249. if (!event->vcpu) {
  250. pr_err("Not enough memory\n");
  251. return false;
  252. }
  253. memset(event->vcpu + old_max_vcpu, 0,
  254. (event->max_vcpu - old_max_vcpu) * sizeof(*event->vcpu));
  255. return true;
  256. }
  257. static struct kvm_event *kvm_alloc_init_event(struct event_key *key)
  258. {
  259. struct kvm_event *event;
  260. event = zalloc(sizeof(*event));
  261. if (!event) {
  262. pr_err("Not enough memory\n");
  263. return NULL;
  264. }
  265. event->key = *key;
  266. return event;
  267. }
  268. static struct kvm_event *find_create_kvm_event(struct event_key *key)
  269. {
  270. struct kvm_event *event;
  271. struct list_head *head;
  272. BUG_ON(key->key == INVALID_KEY);
  273. head = &kvm_events_cache[kvm_events_hash_fn(key->key)];
  274. list_for_each_entry(event, head, hash_entry)
  275. if (event->key.key == key->key && event->key.info == key->info)
  276. return event;
  277. event = kvm_alloc_init_event(key);
  278. if (!event)
  279. return NULL;
  280. list_add(&event->hash_entry, head);
  281. return event;
  282. }
  283. static bool handle_begin_event(struct vcpu_event_record *vcpu_record,
  284. struct event_key *key, u64 timestamp)
  285. {
  286. struct kvm_event *event = NULL;
  287. if (key->key != INVALID_KEY)
  288. event = find_create_kvm_event(key);
  289. vcpu_record->last_event = event;
  290. vcpu_record->start_time = timestamp;
  291. return true;
  292. }
  293. static void
  294. kvm_update_event_stats(struct kvm_event_stats *kvm_stats, u64 time_diff)
  295. {
  296. kvm_stats->time += time_diff;
  297. update_stats(&kvm_stats->stats, time_diff);
  298. }
  299. static double kvm_event_rel_stddev(int vcpu_id, struct kvm_event *event)
  300. {
  301. struct kvm_event_stats *kvm_stats = &event->total;
  302. if (vcpu_id != -1)
  303. kvm_stats = &event->vcpu[vcpu_id];
  304. return rel_stddev_stats(stddev_stats(&kvm_stats->stats),
  305. avg_stats(&kvm_stats->stats));
  306. }
  307. static bool update_kvm_event(struct kvm_event *event, int vcpu_id,
  308. u64 time_diff)
  309. {
  310. kvm_update_event_stats(&event->total, time_diff);
  311. if (!kvm_event_expand(event, vcpu_id))
  312. return false;
  313. kvm_update_event_stats(&event->vcpu[vcpu_id], time_diff);
  314. return true;
  315. }
  316. static bool handle_end_event(struct vcpu_event_record *vcpu_record,
  317. struct event_key *key, u64 timestamp)
  318. {
  319. struct kvm_event *event;
  320. u64 time_begin, time_diff;
  321. event = vcpu_record->last_event;
  322. time_begin = vcpu_record->start_time;
  323. /* The begin event is not caught. */
  324. if (!time_begin)
  325. return true;
  326. /*
  327. * In some case, the 'begin event' only records the start timestamp,
  328. * the actual event is recognized in the 'end event' (e.g. mmio-event).
  329. */
  330. /* Both begin and end events did not get the key. */
  331. if (!event && key->key == INVALID_KEY)
  332. return true;
  333. if (!event)
  334. event = find_create_kvm_event(key);
  335. if (!event)
  336. return false;
  337. vcpu_record->last_event = NULL;
  338. vcpu_record->start_time = 0;
  339. BUG_ON(timestamp < time_begin);
  340. time_diff = timestamp - time_begin;
  341. return update_kvm_event(event, vcpu_record->vcpu_id, time_diff);
  342. }
  343. static struct vcpu_event_record
  344. *per_vcpu_record(struct thread *thread, struct event_format *event, void *data)
  345. {
  346. /* Only kvm_entry records vcpu id. */
  347. if (!thread->priv && kvm_entry_event(event)) {
  348. struct vcpu_event_record *vcpu_record;
  349. vcpu_record = zalloc(sizeof(struct vcpu_event_record));
  350. if (!vcpu_record) {
  351. pr_err("Not enough memory\n");
  352. return NULL;
  353. }
  354. vcpu_record->vcpu_id = raw_field_value(event, "vcpu_id", data);
  355. thread->priv = vcpu_record;
  356. }
  357. return (struct vcpu_event_record *)thread->priv;
  358. }
  359. static bool handle_kvm_event(struct thread *thread, struct event_format *event,
  360. void *data, u64 timestamp)
  361. {
  362. struct vcpu_event_record *vcpu_record;
  363. struct event_key key = {.key = INVALID_KEY};
  364. vcpu_record = per_vcpu_record(thread, event, data);
  365. if (!vcpu_record)
  366. return true;
  367. if (events_ops->is_begin_event(event, data, &key))
  368. return handle_begin_event(vcpu_record, &key, timestamp);
  369. if (events_ops->is_end_event(event, data, &key))
  370. return handle_end_event(vcpu_record, &key, timestamp);
  371. return true;
  372. }
  373. typedef int (*key_cmp_fun)(struct kvm_event*, struct kvm_event*, int);
  374. struct kvm_event_key {
  375. const char *name;
  376. key_cmp_fun key;
  377. };
  378. static int trace_vcpu = -1;
  379. #define GET_EVENT_KEY(func, field) \
  380. static u64 get_event_ ##func(struct kvm_event *event, int vcpu) \
  381. { \
  382. if (vcpu == -1) \
  383. return event->total.field; \
  384. \
  385. if (vcpu >= event->max_vcpu) \
  386. return 0; \
  387. \
  388. return event->vcpu[vcpu].field; \
  389. }
  390. #define COMPARE_EVENT_KEY(func, field) \
  391. GET_EVENT_KEY(func, field) \
  392. static int compare_kvm_event_ ## func(struct kvm_event *one, \
  393. struct kvm_event *two, int vcpu)\
  394. { \
  395. return get_event_ ##func(one, vcpu) > \
  396. get_event_ ##func(two, vcpu); \
  397. }
  398. GET_EVENT_KEY(time, time);
  399. COMPARE_EVENT_KEY(count, stats.n);
  400. COMPARE_EVENT_KEY(mean, stats.mean);
  401. #define DEF_SORT_NAME_KEY(name, compare_key) \
  402. { #name, compare_kvm_event_ ## compare_key }
  403. static struct kvm_event_key keys[] = {
  404. DEF_SORT_NAME_KEY(sample, count),
  405. DEF_SORT_NAME_KEY(time, mean),
  406. { NULL, NULL }
  407. };
  408. static const char *sort_key = "sample";
  409. static key_cmp_fun compare;
  410. static bool select_key(void)
  411. {
  412. int i;
  413. for (i = 0; keys[i].name; i++) {
  414. if (!strcmp(keys[i].name, sort_key)) {
  415. compare = keys[i].key;
  416. return true;
  417. }
  418. }
  419. pr_err("Unknown compare key:%s\n", sort_key);
  420. return false;
  421. }
  422. static struct rb_root result;
  423. static void insert_to_result(struct kvm_event *event, key_cmp_fun bigger,
  424. int vcpu)
  425. {
  426. struct rb_node **rb = &result.rb_node;
  427. struct rb_node *parent = NULL;
  428. struct kvm_event *p;
  429. while (*rb) {
  430. p = container_of(*rb, struct kvm_event, rb);
  431. parent = *rb;
  432. if (bigger(event, p, vcpu))
  433. rb = &(*rb)->rb_left;
  434. else
  435. rb = &(*rb)->rb_right;
  436. }
  437. rb_link_node(&event->rb, parent, rb);
  438. rb_insert_color(&event->rb, &result);
  439. }
  440. static void update_total_count(struct kvm_event *event, int vcpu)
  441. {
  442. total_count += get_event_count(event, vcpu);
  443. total_time += get_event_time(event, vcpu);
  444. }
  445. static bool event_is_valid(struct kvm_event *event, int vcpu)
  446. {
  447. return !!get_event_count(event, vcpu);
  448. }
  449. static void sort_result(int vcpu)
  450. {
  451. unsigned int i;
  452. struct kvm_event *event;
  453. for (i = 0; i < EVENTS_CACHE_SIZE; i++)
  454. list_for_each_entry(event, &kvm_events_cache[i], hash_entry)
  455. if (event_is_valid(event, vcpu)) {
  456. update_total_count(event, vcpu);
  457. insert_to_result(event, compare, vcpu);
  458. }
  459. }
  460. /* returns left most element of result, and erase it */
  461. static struct kvm_event *pop_from_result(void)
  462. {
  463. struct rb_node *node = rb_first(&result);
  464. if (!node)
  465. return NULL;
  466. rb_erase(node, &result);
  467. return container_of(node, struct kvm_event, rb);
  468. }
  469. static void print_vcpu_info(int vcpu)
  470. {
  471. pr_info("Analyze events for ");
  472. if (vcpu == -1)
  473. pr_info("all VCPUs:\n\n");
  474. else
  475. pr_info("VCPU %d:\n\n", vcpu);
  476. }
  477. static void print_result(int vcpu)
  478. {
  479. char decode[20];
  480. struct kvm_event *event;
  481. pr_info("\n\n");
  482. print_vcpu_info(vcpu);
  483. pr_info("%20s ", events_ops->name);
  484. pr_info("%10s ", "Samples");
  485. pr_info("%9s ", "Samples%");
  486. pr_info("%9s ", "Time%");
  487. pr_info("%16s ", "Avg time");
  488. pr_info("\n\n");
  489. while ((event = pop_from_result())) {
  490. u64 ecount, etime;
  491. ecount = get_event_count(event, vcpu);
  492. etime = get_event_time(event, vcpu);
  493. events_ops->decode_key(&event->key, decode);
  494. pr_info("%20s ", decode);
  495. pr_info("%10llu ", (unsigned long long)ecount);
  496. pr_info("%8.2f%% ", (double)ecount / total_count * 100);
  497. pr_info("%8.2f%% ", (double)etime / total_time * 100);
  498. pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount/1e3,
  499. kvm_event_rel_stddev(vcpu, event));
  500. pr_info("\n");
  501. }
  502. pr_info("\nTotal Samples:%lld, Total events handled time:%.2fus.\n\n",
  503. (unsigned long long)total_count, total_time / 1e3);
  504. }
  505. static int process_sample_event(struct perf_tool *tool __maybe_unused,
  506. union perf_event *event,
  507. struct perf_sample *sample,
  508. struct perf_evsel *evsel,
  509. struct machine *machine)
  510. {
  511. struct thread *thread = machine__findnew_thread(machine, sample->tid);
  512. if (thread == NULL) {
  513. pr_debug("problem processing %d event, skipping it.\n",
  514. event->header.type);
  515. return -1;
  516. }
  517. if (!handle_kvm_event(thread, evsel->tp_format, sample->raw_data,
  518. sample->time))
  519. return -1;
  520. return 0;
  521. }
  522. static struct perf_tool eops = {
  523. .sample = process_sample_event,
  524. .comm = perf_event__process_comm,
  525. .ordered_samples = true,
  526. };
  527. static int get_cpu_isa(struct perf_session *session)
  528. {
  529. char *cpuid;
  530. int isa;
  531. cpuid = perf_header__read_feature(session, HEADER_CPUID);
  532. if (!cpuid) {
  533. pr_err("read HEADER_CPUID failed.\n");
  534. return -ENOTSUP;
  535. }
  536. if (strstr(cpuid, "Intel"))
  537. isa = 1;
  538. else if (strstr(cpuid, "AMD"))
  539. isa = 0;
  540. else {
  541. pr_err("CPU %s is not supported.\n", cpuid);
  542. isa = -ENOTSUP;
  543. }
  544. free(cpuid);
  545. return isa;
  546. }
  547. static const char *file_name;
  548. static int read_events(void)
  549. {
  550. struct perf_session *kvm_session;
  551. int ret;
  552. kvm_session = perf_session__new(file_name, O_RDONLY, 0, false, &eops);
  553. if (!kvm_session) {
  554. pr_err("Initializing perf session failed\n");
  555. return -EINVAL;
  556. }
  557. if (!perf_session__has_traces(kvm_session, "kvm record"))
  558. return -EINVAL;
  559. /*
  560. * Do not use 'isa' recorded in kvm_exit tracepoint since it is not
  561. * traced in the old kernel.
  562. */
  563. ret = get_cpu_isa(kvm_session);
  564. if (ret < 0)
  565. return ret;
  566. cpu_isa = ret;
  567. return perf_session__process_events(kvm_session, &eops);
  568. }
  569. static bool verify_vcpu(int vcpu)
  570. {
  571. if (vcpu != -1 && vcpu < 0) {
  572. pr_err("Invalid vcpu:%d.\n", vcpu);
  573. return false;
  574. }
  575. return true;
  576. }
  577. static int kvm_events_report_vcpu(int vcpu)
  578. {
  579. int ret = -EINVAL;
  580. if (!verify_vcpu(vcpu))
  581. goto exit;
  582. if (!select_key())
  583. goto exit;
  584. if (!register_kvm_events_ops())
  585. goto exit;
  586. init_kvm_event_record();
  587. setup_pager();
  588. ret = read_events();
  589. if (ret)
  590. goto exit;
  591. sort_result(vcpu);
  592. print_result(vcpu);
  593. exit:
  594. return ret;
  595. }
  596. static const char * const record_args[] = {
  597. "record",
  598. "-R",
  599. "-f",
  600. "-m", "1024",
  601. "-c", "1",
  602. "-e", "kvm:kvm_entry",
  603. "-e", "kvm:kvm_exit",
  604. "-e", "kvm:kvm_mmio",
  605. "-e", "kvm:kvm_pio",
  606. };
  607. #define STRDUP_FAIL_EXIT(s) \
  608. ({ char *_p; \
  609. _p = strdup(s); \
  610. if (!_p) \
  611. return -ENOMEM; \
  612. _p; \
  613. })
  614. static int kvm_events_record(int argc, const char **argv)
  615. {
  616. unsigned int rec_argc, i, j;
  617. const char **rec_argv;
  618. rec_argc = ARRAY_SIZE(record_args) + argc + 2;
  619. rec_argv = calloc(rec_argc + 1, sizeof(char *));
  620. if (rec_argv == NULL)
  621. return -ENOMEM;
  622. for (i = 0; i < ARRAY_SIZE(record_args); i++)
  623. rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]);
  624. rec_argv[i++] = STRDUP_FAIL_EXIT("-o");
  625. rec_argv[i++] = STRDUP_FAIL_EXIT(file_name);
  626. for (j = 1; j < (unsigned int)argc; j++, i++)
  627. rec_argv[i] = argv[j];
  628. return cmd_record(i, rec_argv, NULL);
  629. }
  630. static const char * const kvm_events_report_usage[] = {
  631. "perf kvm stat report [<options>]",
  632. NULL
  633. };
  634. static const struct option kvm_events_report_options[] = {
  635. OPT_STRING(0, "event", &report_event, "report event",
  636. "event for reporting: vmexit, mmio, ioport"),
  637. OPT_INTEGER(0, "vcpu", &trace_vcpu,
  638. "vcpu id to report"),
  639. OPT_STRING('k', "key", &sort_key, "sort-key",
  640. "key for sorting: sample(sort by samples number)"
  641. " time (sort by avg time)"),
  642. OPT_END()
  643. };
  644. static int kvm_events_report(int argc, const char **argv)
  645. {
  646. symbol__init();
  647. if (argc) {
  648. argc = parse_options(argc, argv,
  649. kvm_events_report_options,
  650. kvm_events_report_usage, 0);
  651. if (argc)
  652. usage_with_options(kvm_events_report_usage,
  653. kvm_events_report_options);
  654. }
  655. return kvm_events_report_vcpu(trace_vcpu);
  656. }
  657. static void print_kvm_stat_usage(void)
  658. {
  659. printf("Usage: perf kvm stat <command>\n\n");
  660. printf("# Available commands:\n");
  661. printf("\trecord: record kvm events\n");
  662. printf("\treport: report statistical data of kvm events\n");
  663. printf("\nOtherwise, it is the alias of 'perf stat':\n");
  664. }
  665. static int kvm_cmd_stat(int argc, const char **argv)
  666. {
  667. if (argc == 1) {
  668. print_kvm_stat_usage();
  669. goto perf_stat;
  670. }
  671. if (!strncmp(argv[1], "rec", 3))
  672. return kvm_events_record(argc - 1, argv + 1);
  673. if (!strncmp(argv[1], "rep", 3))
  674. return kvm_events_report(argc - 1 , argv + 1);
  675. perf_stat:
  676. return cmd_stat(argc, argv, NULL);
  677. }
  678. static char name_buffer[256];
  679. static const char * const kvm_usage[] = {
  680. "perf kvm [<options>] {top|record|report|diff|buildid-list|stat}",
  681. NULL
  682. };
  683. static const struct option kvm_options[] = {
  684. OPT_STRING('i', "input", &file_name, "file",
  685. "Input file name"),
  686. OPT_STRING('o', "output", &file_name, "file",
  687. "Output file name"),
  688. OPT_BOOLEAN(0, "guest", &perf_guest,
  689. "Collect guest os data"),
  690. OPT_BOOLEAN(0, "host", &perf_host,
  691. "Collect host os data"),
  692. OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory",
  693. "guest mount directory under which every guest os"
  694. " instance has a subdir"),
  695. OPT_STRING(0, "guestvmlinux", &symbol_conf.default_guest_vmlinux_name,
  696. "file", "file saving guest os vmlinux"),
  697. OPT_STRING(0, "guestkallsyms", &symbol_conf.default_guest_kallsyms,
  698. "file", "file saving guest os /proc/kallsyms"),
  699. OPT_STRING(0, "guestmodules", &symbol_conf.default_guest_modules,
  700. "file", "file saving guest os /proc/modules"),
  701. OPT_END()
  702. };
  703. static int __cmd_record(int argc, const char **argv)
  704. {
  705. int rec_argc, i = 0, j;
  706. const char **rec_argv;
  707. rec_argc = argc + 2;
  708. rec_argv = calloc(rec_argc + 1, sizeof(char *));
  709. rec_argv[i++] = strdup("record");
  710. rec_argv[i++] = strdup("-o");
  711. rec_argv[i++] = strdup(file_name);
  712. for (j = 1; j < argc; j++, i++)
  713. rec_argv[i] = argv[j];
  714. BUG_ON(i != rec_argc);
  715. return cmd_record(i, rec_argv, NULL);
  716. }
  717. static int __cmd_report(int argc, const char **argv)
  718. {
  719. int rec_argc, i = 0, j;
  720. const char **rec_argv;
  721. rec_argc = argc + 2;
  722. rec_argv = calloc(rec_argc + 1, sizeof(char *));
  723. rec_argv[i++] = strdup("report");
  724. rec_argv[i++] = strdup("-i");
  725. rec_argv[i++] = strdup(file_name);
  726. for (j = 1; j < argc; j++, i++)
  727. rec_argv[i] = argv[j];
  728. BUG_ON(i != rec_argc);
  729. return cmd_report(i, rec_argv, NULL);
  730. }
  731. static int __cmd_buildid_list(int argc, const char **argv)
  732. {
  733. int rec_argc, i = 0, j;
  734. const char **rec_argv;
  735. rec_argc = argc + 2;
  736. rec_argv = calloc(rec_argc + 1, sizeof(char *));
  737. rec_argv[i++] = strdup("buildid-list");
  738. rec_argv[i++] = strdup("-i");
  739. rec_argv[i++] = strdup(file_name);
  740. for (j = 1; j < argc; j++, i++)
  741. rec_argv[i] = argv[j];
  742. BUG_ON(i != rec_argc);
  743. return cmd_buildid_list(i, rec_argv, NULL);
  744. }
  745. int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
  746. {
  747. perf_host = 0;
  748. perf_guest = 1;
  749. argc = parse_options(argc, argv, kvm_options, kvm_usage,
  750. PARSE_OPT_STOP_AT_NON_OPTION);
  751. if (!argc)
  752. usage_with_options(kvm_usage, kvm_options);
  753. if (!perf_host)
  754. perf_guest = 1;
  755. if (!file_name) {
  756. if (perf_host && !perf_guest)
  757. sprintf(name_buffer, "perf.data.host");
  758. else if (!perf_host && perf_guest)
  759. sprintf(name_buffer, "perf.data.guest");
  760. else
  761. sprintf(name_buffer, "perf.data.kvm");
  762. file_name = name_buffer;
  763. }
  764. if (!strncmp(argv[0], "rec", 3))
  765. return __cmd_record(argc, argv);
  766. else if (!strncmp(argv[0], "rep", 3))
  767. return __cmd_report(argc, argv);
  768. else if (!strncmp(argv[0], "diff", 4))
  769. return cmd_diff(argc, argv, NULL);
  770. else if (!strncmp(argv[0], "top", 3))
  771. return cmd_top(argc, argv, NULL);
  772. else if (!strncmp(argv[0], "buildid-list", 12))
  773. return __cmd_buildid_list(argc, argv);
  774. else if (!strncmp(argv[0], "stat", 4))
  775. return kvm_cmd_stat(argc, argv);
  776. else
  777. usage_with_options(kvm_usage, kvm_options);
  778. return 0;
  779. }