#include <palacios/vmm_telemetry.h>
#include <palacios/svm_handler.h>
#include <palacios/vmm_rbtree.h>
+#include <palacios/vmm_sprintf.h>
#ifdef CONFIG_TELEMETRY_GRANULARITY
#define DEFAULT_GRANULARITY CONFIG_TELEMETRY_GRANULARITY
#else
-#define DEFAULT_GRANULARITY 20000
+#define DEFAULT_GRANULARITY 50000
#endif
struct telemetry_cb {
- void (*telemetry_fn)(struct guest_info * info, void * private_data);
+ void (*telemetry_fn)(struct v3_vm_info * vm, void * private_data, char * hdr);
void * private_data;
struct list_head cb_node;
};
-void v3_init_telemetry(struct guest_info * info) {
- struct v3_telemetry_state * telemetry = &(info->telemetry);
+static int free_callback(struct v3_vm_info * vm, struct telemetry_cb * cb);
+static int free_exit(struct guest_info * core, struct exit_event * event);
+
+
+void v3_init_telemetry(struct v3_vm_info * vm) {
+ struct v3_telemetry_state * telemetry = &(vm->telemetry);
- telemetry->exit_cnt = 0;
- telemetry->vmm_start_tsc = 0;
- telemetry->prev_tsc = 0;
telemetry->invoke_cnt = 0;
telemetry->granularity = DEFAULT_GRANULARITY;
+ telemetry->prev_tsc = 0;
- telemetry->exit_root.rb_node = NULL;
INIT_LIST_HEAD(&(telemetry->cb_list));
}
+void v3_deinit_telemetry(struct v3_vm_info * vm) {
+ struct telemetry_cb * cb = NULL;
+ struct telemetry_cb * tmp = NULL;
+
+ list_for_each_entry_safe(cb, tmp, &(vm->telemetry.cb_list), cb_node) {
+ free_callback(vm, cb);
+ }
+}
+
+
+void v3_init_core_telemetry(struct guest_info * core) {
+ struct v3_core_telemetry * telemetry = &(core->core_telem);
+
+ telemetry->exit_cnt = 0;
+ telemetry->vmm_start_tsc = 0;
+
+ telemetry->vm_telem = &(core->vm_info->telemetry);
+
+ telemetry->exit_root.rb_node = NULL;
+}
+
+void v3_deinit_core_telemetry(struct guest_info * core) {
+ struct rb_node * node = v3_rb_first(&(core->core_telem.exit_root));
+ struct exit_event * evt = NULL;
+
+ while (node) {
+ evt = rb_entry(node, struct exit_event, tree_node);
+ node = v3_rb_next(node);
+
+ free_exit(core, evt);
+ }
+}
+
static inline struct exit_event * __insert_event(struct guest_info * info,
struct exit_event * evt) {
- struct rb_node ** p = &(info->telemetry.exit_root.rb_node);
+ struct rb_node ** p = &(info->core_telem.exit_root.rb_node);
struct rb_node * parent = NULL;
struct exit_event * tmp_evt = NULL;
return ret;
}
- v3_rb_insert_color(&(evt->tree_node), &(info->telemetry.exit_root));
+ v3_rb_insert_color(&(evt->tree_node), &(info->core_telem.exit_root));
return NULL;
}
static struct exit_event * get_exit(struct guest_info * info, uint_t exit_code) {
- struct rb_node * n = info->telemetry.exit_root.rb_node;
+ struct rb_node * n = info->core_telem.exit_root.rb_node;
struct exit_event * evt = NULL;
while (n) {
return evt;
}
+
+
+static int free_exit(struct guest_info * core, struct exit_event * evt) {
+ v3_rb_erase(&(evt->tree_node), &(core->core_telem.exit_root));
+ V3_Free(evt);
+ return 0;
+}
+
+
void v3_telemetry_start_exit(struct guest_info * info) {
- rdtscll(info->telemetry.vmm_start_tsc);
+ rdtscll(info->core_telem.vmm_start_tsc);
}
void v3_telemetry_end_exit(struct guest_info * info, uint_t exit_code) {
- struct v3_telemetry_state * telemetry = &(info->telemetry);
+ struct v3_core_telemetry * telemetry = &(info->core_telem);
struct exit_event * evt = NULL;
uint64_t end_tsc = 0;
// check if the exit count has expired
- if ((telemetry->exit_cnt % telemetry->granularity) == 0) {
- v3_print_telemetry(info);
+ if ((telemetry->exit_cnt % telemetry->vm_telem->granularity) == 0) {
+ v3_print_telemetry(info->vm_info);
}
}
-void v3_add_telemetry_cb(struct guest_info * info,
- void (*telemetry_fn)(struct guest_info * info, void * private_data),
- void * private_data) {
- struct v3_telemetry_state * telemetry = &(info->telemetry);
+void v3_add_telemetry_cb(struct v3_vm_info * vm,
+ void (*telemetry_fn)(struct v3_vm_info * vm, void * private_data, char * hdr),
+ void * private_data) {
+ struct v3_telemetry_state * telemetry = &(vm->telemetry);
struct telemetry_cb * cb = (struct telemetry_cb *)V3_Malloc(sizeof(struct telemetry_cb));
cb->private_data = private_data;
}
-void v3_print_telemetry(struct guest_info * info) {
- struct v3_telemetry_state * telemetry = &(info->telemetry);
+
+static int free_callback(struct v3_vm_info * vm, struct telemetry_cb * cb) {
+ list_del(&(cb->cb_node));
+ V3_Free(cb);
+
+ return 0;
+}
+
+
+void v3_print_telemetry(struct v3_vm_info * vm) {
+ struct v3_telemetry_state * telemetry = &(vm->telemetry);
uint64_t invoke_tsc = 0;
+ char hdr_buf[32];
+ int i;
rdtscll(invoke_tsc);
- V3_Print("Telemetry (%d)\n", telemetry->invoke_cnt++);
- V3_Print("\ttelemetry window tsc cnt: %d\n", (uint32_t)(invoke_tsc - telemetry->prev_tsc));
+ snprintf(hdr_buf, 32, "telem.%d>", telemetry->invoke_cnt++);
+
+ V3_Print("%stelemetry window tsc cnt: %d\n", hdr_buf, (uint32_t)(invoke_tsc - telemetry->prev_tsc));
+
// Exit Telemetry
- {
+ for (i = 0; i < vm->num_cores; i++) {
+ struct guest_info * core = &(vm->cores[i]);
struct exit_event * evt = NULL;
- struct rb_node * node = v3_rb_first(&(info->telemetry.exit_root));
+ struct rb_node * node = v3_rb_first(&(core->core_telem.exit_root));
+ V3_Print("Exit information for Core %d\n", core->cpu_id);
+
+ if (!node) {
+ V3_Print("No information yet for this core\n");
+ continue;
+ }
+
do {
evt = rb_entry(node, struct exit_event, tree_node);
const char * code_str = vmexit_code_to_str(evt->exit_code);
- V3_Print("%s:%sCnt=%u,%sAvg. Time=%u\n",
- code_str,
- (strlen(code_str) > 14) ? "\t" : "\t\t",
- evt->cnt,
- (evt->cnt >= 100) ? "\t" : "\t\t",
- (uint32_t)(evt->handler_time / evt->cnt));
-
+ V3_Print("%s%s:%sCnt=%u,%sAvg. Time=%u\n",
+ hdr_buf,
+ code_str,
+ (strlen(code_str) > 13) ? "\t" : "\t\t",
+ evt->cnt,
+ (evt->cnt >= 100) ? "\t" : "\t\t",
+ (uint32_t)(evt->handler_time / evt->cnt));
} while ((node = v3_rb_next(node)));
}
struct telemetry_cb * cb = NULL;
list_for_each_entry(cb, &(telemetry->cb_list), cb_node) {
- cb->telemetry_fn(info, cb->private_data);
+ cb->telemetry_fn(vm, cb->private_data, hdr_buf);
}
}
telemetry->prev_tsc = invoke_tsc;
+
+ V3_Print("%s Telemetry done\n", hdr_buf);
+
}