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/vmx_handler.h>
24 #include <palacios/vmm_rbtree.h>
25 #include <palacios/vmm_sprintf.h>
29 #ifdef V3_CONFIG_TELEMETRY_GRANULARITY
30 #define DEFAULT_GRANULARITY V3_CONFIG_TELEMETRY_GRANULARITY
32 #define DEFAULT_GRANULARITY 50000
39 void (*telemetry_fn)(struct v3_vm_info * vm, void * private_data, char * hdr);
42 struct list_head cb_node;
49 uint64_t handler_time;
51 struct rb_node tree_node;
55 static int free_callback(struct v3_vm_info * vm, struct telemetry_cb * cb);
56 static int free_exit(struct guest_info * core, struct exit_event * event);
59 void v3_init_telemetry(struct v3_vm_info * vm) {
60 struct v3_telemetry_state * telemetry = &(vm->telemetry);
62 telemetry->invoke_cnt = 0;
63 telemetry->granularity = DEFAULT_GRANULARITY;
65 telemetry->prev_tsc = 0;
67 INIT_LIST_HEAD(&(telemetry->cb_list));
70 void v3_deinit_telemetry(struct v3_vm_info * vm) {
71 struct telemetry_cb * cb = NULL;
72 struct telemetry_cb * tmp = NULL;
74 list_for_each_entry_safe(cb, tmp, &(vm->telemetry.cb_list), cb_node) {
75 free_callback(vm, cb);
80 void v3_init_core_telemetry(struct guest_info * core) {
81 struct v3_core_telemetry * telemetry = &(core->core_telem);
83 telemetry->exit_cnt = 0;
84 telemetry->vmm_start_tsc = 0;
86 telemetry->vm_telem = &(core->vm_info->telemetry);
88 telemetry->exit_root.rb_node = NULL;
91 void v3_deinit_core_telemetry(struct guest_info * core) {
92 struct rb_node * node = v3_rb_first(&(core->core_telem.exit_root));
93 struct exit_event * evt = NULL;
96 evt = rb_entry(node, struct exit_event, tree_node);
97 node = v3_rb_next(node);
105 static inline struct exit_event * __insert_event(struct guest_info * info,
106 struct exit_event * evt) {
107 struct rb_node ** p = &(info->core_telem.exit_root.rb_node);
108 struct rb_node * parent = NULL;
109 struct exit_event * tmp_evt = NULL;
113 tmp_evt = rb_entry(parent, struct exit_event, tree_node);
115 if (evt->exit_code < tmp_evt->exit_code) {
117 } else if (evt->exit_code > tmp_evt->exit_code) {
123 rb_link_node(&(evt->tree_node), parent, p);
128 static inline struct exit_event * insert_event(struct guest_info * info,
129 struct exit_event * evt) {
130 struct exit_event * ret;
132 if ((ret = __insert_event(info, evt))) {
136 v3_rb_insert_color(&(evt->tree_node), &(info->core_telem.exit_root));
142 static struct exit_event * get_exit(struct guest_info * info, uint_t exit_code) {
143 struct rb_node * n = info->core_telem.exit_root.rb_node;
144 struct exit_event * evt = NULL;
147 evt = rb_entry(n, struct exit_event, tree_node);
149 if (exit_code < evt->exit_code) {
151 } else if (exit_code > evt->exit_code) {
162 static inline struct exit_event * create_exit(uint_t exit_code) {
163 struct exit_event * evt = V3_Malloc(sizeof(struct exit_event));
166 PrintError(VM_NONE, VCORE_NONE, "Cannot allocate in createing exit in telemetry\n");
170 evt->exit_code = exit_code;
172 evt->handler_time = 0;
179 static int free_exit(struct guest_info * core, struct exit_event * evt) {
180 v3_rb_erase(&(evt->tree_node), &(core->core_telem.exit_root));
186 void v3_telemetry_start_exit(struct guest_info * info) {
187 rdtscll(info->core_telem.vmm_start_tsc);
191 void v3_telemetry_end_exit(struct guest_info * info, uint_t exit_code) {
192 struct v3_core_telemetry * telemetry = &(info->core_telem);
193 struct exit_event * evt = NULL;
194 uint64_t end_tsc = 0;
198 evt = get_exit(info, exit_code);
201 evt = create_exit(exit_code);
202 insert_event(info, evt);
205 evt->handler_time += end_tsc - telemetry->vmm_start_tsc;
208 telemetry->exit_cnt++;
212 // check if the exit count has expired
213 if ((telemetry->exit_cnt % telemetry->vm_telem->granularity) == 0) {
214 v3_print_telemetry(info->vm_info, info);
221 void v3_add_telemetry_cb(struct v3_vm_info * vm,
222 void (*telemetry_fn)(struct v3_vm_info * vm, void * private_data, char * hdr),
223 void * private_data) {
224 struct v3_telemetry_state * telemetry = &(vm->telemetry);
225 struct telemetry_cb * cb = (struct telemetry_cb *)V3_Malloc(sizeof(struct telemetry_cb));
228 PrintError(vm, VCORE_NONE, "Cannot allocate in adding a telemtry callback\n");
232 cb->private_data = private_data;
233 cb->telemetry_fn = telemetry_fn;
235 list_add(&(cb->cb_node), &(telemetry->cb_list));
240 static int free_callback(struct v3_vm_info * vm, struct telemetry_cb * cb) {
241 list_del(&(cb->cb_node));
248 static void telemetry_header(struct v3_vm_info *vm, char *hdr_buf, int len)
250 struct v3_telemetry_state * telemetry = &(vm->telemetry);
251 snprintf(hdr_buf, len, "telem.%d>", telemetry->invoke_cnt);
254 static void print_telemetry_start(struct v3_vm_info *vm, char *hdr_buf)
256 struct v3_telemetry_state * telemetry = &(vm->telemetry);
257 uint64_t invoke_tsc = 0;
259 V3_Print(vm, VCORE_NONE, "%stelemetry window tsc cnt: %u\n", hdr_buf, (uint32_t)(invoke_tsc - telemetry->prev_tsc));
260 telemetry->prev_tsc = invoke_tsc;
263 static void print_telemetry_end(struct v3_vm_info *vm, char *hdr_buf)
265 V3_Print(vm, VCORE_NONE, "%s Telemetry done\n", hdr_buf);
268 static void print_core_telemetry(struct guest_info * core, char *hdr_buf)
270 struct exit_event * evt = NULL;
271 struct rb_node * node = v3_rb_first(&(core->core_telem.exit_root));
273 V3_Print(core->vm_info, core, "Exit information for Core %d\n", core->vcpu_id);
276 V3_Print(core->vm_info, core, "No information yet for this core\n");
281 extern v3_cpu_arch_t v3_mach_type;
282 const char * code_str = NULL;
284 evt = rb_entry(node, struct exit_event, tree_node);
286 switch (v3_mach_type) {
288 case V3_SVM_REV3_CPU:
290 code_str = v3_svm_exit_code_to_str(evt->exit_code);
294 case V3_VMX_EPT_UG_CPU:
295 code_str = v3_vmx_exit_code_to_str(evt->exit_code);
302 V3_Print(core->vm_info, core, "%s%s:%sCnt=%u,%sAvg. Time=%u\n",
304 (strlen(code_str) > 13) ? "\t" : "\t\t",
306 (evt->cnt >= 100) ? "\t" : "\t\t",
307 (uint32_t)(evt->handler_time / evt->cnt));
308 } while ((node = v3_rb_next(node)));
312 void v3_print_core_telemetry(struct guest_info * core ) {
313 struct v3_vm_info *vm = core->vm_info;
314 struct v3_telemetry_state * telemetry = &(vm->telemetry);
317 telemetry_header(vm, hdr_buf, 32);
318 telemetry->invoke_cnt++; // XXX this increment isn't atomic and probably should be
320 print_telemetry_start(vm, hdr_buf);
321 print_core_telemetry(core, hdr_buf);
322 print_telemetry_end(vm, hdr_buf);
327 static void telemetry_callbacks(struct v3_vm_info * vm, char *hdr_buf)
329 struct v3_telemetry_state * telemetry = &(vm->telemetry);
330 // Registered callbacks
332 struct telemetry_cb * cb = NULL;
334 list_for_each_entry(cb, &(telemetry->cb_list), cb_node) {
335 cb->telemetry_fn(vm, cb->private_data, hdr_buf);
340 void v3_print_global_telemetry(struct v3_vm_info * vm) {
341 struct v3_telemetry_state * telemetry = &(vm->telemetry);
344 telemetry_header(vm, hdr_buf, 32);
345 telemetry->invoke_cnt++; // XXX this increment isn't atomic and probably should be
347 print_telemetry_start( vm, hdr_buf );
348 telemetry_callbacks( vm, hdr_buf );
349 print_telemetry_end( vm, hdr_buf );
352 void v3_print_telemetry(struct v3_vm_info * vm, struct guest_info * core )
354 struct v3_telemetry_state * telemetry = &(vm->telemetry);
357 telemetry_header(vm, hdr_buf, 32);
358 telemetry->invoke_cnt++; // XXX this increment isn't atomic and probably should be
360 print_telemetry_start(vm, hdr_buf);
361 print_core_telemetry(core, hdr_buf);
362 telemetry_callbacks(vm, hdr_buf);
363 print_telemetry_end(vm, hdr_buf);