2 * This file is part of the Palacios Virtual Machine Monitor developed
3 * by the V3VEE Project with funding from the United States National
4 * Science Foundation and the Department of Energy.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
10 * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
11 * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
12 * All rights reserved.
14 * Author: Jack Lange <jarusl@cs.northwestern.edu>
16 * This is free software. You are permitted to use,
17 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
20 #include <palacios/vmm_types.h>
21 #include <palacios/vmm_telemetry.h>
22 #include <palacios/svm_handler.h>
23 #include <palacios/vmm_rbtree.h>
24 #include <palacios/vmm_sprintf.h>
27 #ifdef CONFIG_TELEMETRY_GRANULARITY
28 #define DEFAULT_GRANULARITY CONFIG_TELEMETRY_GRANULARITY
30 #define DEFAULT_GRANULARITY 50000
37 void (*telemetry_fn)(struct v3_vm_info * vm, void * private_data, char * hdr);
40 struct list_head cb_node;
47 uint64_t handler_time;
49 struct rb_node tree_node;
53 void v3_init_telemetry(struct v3_vm_info * vm) {
54 struct v3_telemetry_state * telemetry = &(vm->telemetry);
56 telemetry->invoke_cnt = 0;
57 telemetry->granularity = DEFAULT_GRANULARITY;
59 telemetry->prev_tsc = 0;
61 INIT_LIST_HEAD(&(telemetry->cb_list));
64 void v3_init_core_telemetry(struct guest_info * core) {
65 struct v3_core_telemetry * telemetry = &(core->core_telem);
67 telemetry->exit_cnt = 0;
68 telemetry->vmm_start_tsc = 0;
70 telemetry->vm_telem = &(core->vm_info->telemetry);
72 telemetry->exit_root.rb_node = NULL;
77 static inline struct exit_event * __insert_event(struct guest_info * info,
78 struct exit_event * evt) {
79 struct rb_node ** p = &(info->core_telem.exit_root.rb_node);
80 struct rb_node * parent = NULL;
81 struct exit_event * tmp_evt = NULL;
85 tmp_evt = rb_entry(parent, struct exit_event, tree_node);
87 if (evt->exit_code < tmp_evt->exit_code) {
89 } else if (evt->exit_code > tmp_evt->exit_code) {
95 rb_link_node(&(evt->tree_node), parent, p);
100 static inline struct exit_event * insert_event(struct guest_info * info,
101 struct exit_event * evt) {
102 struct exit_event * ret;
104 if ((ret = __insert_event(info, evt))) {
108 v3_rb_insert_color(&(evt->tree_node), &(info->core_telem.exit_root));
114 static struct exit_event * get_exit(struct guest_info * info, uint_t exit_code) {
115 struct rb_node * n = info->core_telem.exit_root.rb_node;
116 struct exit_event * evt = NULL;
119 evt = rb_entry(n, struct exit_event, tree_node);
121 if (exit_code < evt->exit_code) {
123 } else if (exit_code > evt->exit_code) {
134 static inline struct exit_event * create_exit(uint_t exit_code) {
135 struct exit_event * evt = V3_Malloc(sizeof(struct exit_event));
137 evt->exit_code = exit_code;
139 evt->handler_time = 0;
144 void v3_telemetry_start_exit(struct guest_info * info) {
145 rdtscll(info->core_telem.vmm_start_tsc);
149 void v3_telemetry_end_exit(struct guest_info * info, uint_t exit_code) {
150 struct v3_core_telemetry * telemetry = &(info->core_telem);
151 struct exit_event * evt = NULL;
152 uint64_t end_tsc = 0;
156 evt = get_exit(info, exit_code);
159 evt = create_exit(exit_code);
160 insert_event(info, evt);
163 evt->handler_time += end_tsc - telemetry->vmm_start_tsc;
166 telemetry->exit_cnt++;
170 // check if the exit count has expired
171 if ((telemetry->exit_cnt % telemetry->vm_telem->granularity) == 0) {
172 v3_print_telemetry(info->vm_info);
179 void v3_add_telemetry_cb(struct v3_vm_info * vm,
180 void (*telemetry_fn)(struct v3_vm_info * vm, void * private_data, char * hdr),
181 void * private_data) {
182 struct v3_telemetry_state * telemetry = &(vm->telemetry);
183 struct telemetry_cb * cb = (struct telemetry_cb *)V3_Malloc(sizeof(struct telemetry_cb));
185 cb->private_data = private_data;
186 cb->telemetry_fn = telemetry_fn;
188 list_add(&(cb->cb_node), &(telemetry->cb_list));
193 void v3_print_telemetry(struct v3_vm_info * vm) {
194 struct v3_telemetry_state * telemetry = &(vm->telemetry);
195 uint64_t invoke_tsc = 0;
201 snprintf(hdr_buf, 32, "telem.%d>", telemetry->invoke_cnt++);
203 V3_Print("%stelemetry window tsc cnt: %d\n", hdr_buf, (uint32_t)(invoke_tsc - telemetry->prev_tsc));
207 for (i = 0; i < vm->num_cores; i++) {
208 struct guest_info * core = &(vm->cores[i]);
209 struct exit_event * evt = NULL;
210 struct rb_node * node = v3_rb_first(&(core->core_telem.exit_root));
212 V3_Print("Exit information for Core %d\n", core->cpu_id);
215 evt = rb_entry(node, struct exit_event, tree_node);
216 const char * code_str = vmexit_code_to_str(evt->exit_code);
218 V3_Print("%s%s:%sCnt=%u,%sAvg. Time=%u\n",
221 (strlen(code_str) > 13) ? "\t" : "\t\t",
223 (evt->cnt >= 100) ? "\t" : "\t\t",
224 (uint32_t)(evt->handler_time / evt->cnt));
225 } while ((node = v3_rb_next(node)));
229 // Registered callbacks
231 struct telemetry_cb * cb = NULL;
233 list_for_each_entry(cb, &(telemetry->cb_list), cb_node) {
234 cb->telemetry_fn(vm, cb->private_data, hdr_buf);
238 telemetry->prev_tsc = invoke_tsc;
240 V3_Print("%s Telemetry done\n", hdr_buf);