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 guest_info * info, 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 guest_info * info) {
54 struct v3_telemetry_state * telemetry = &(info->telemetry);
56 telemetry->exit_cnt = 0;
57 telemetry->vmm_start_tsc = 0;
58 telemetry->prev_tsc = 0;
59 telemetry->invoke_cnt = 0;
60 telemetry->granularity = DEFAULT_GRANULARITY;
63 telemetry->exit_root.rb_node = NULL;
64 INIT_LIST_HEAD(&(telemetry->cb_list));
69 static inline struct exit_event * __insert_event(struct guest_info * info,
70 struct exit_event * evt) {
71 struct rb_node ** p = &(info->telemetry.exit_root.rb_node);
72 struct rb_node * parent = NULL;
73 struct exit_event * tmp_evt = NULL;
77 tmp_evt = rb_entry(parent, struct exit_event, tree_node);
79 if (evt->exit_code < tmp_evt->exit_code) {
81 } else if (evt->exit_code > tmp_evt->exit_code) {
87 rb_link_node(&(evt->tree_node), parent, p);
92 static inline struct exit_event * insert_event(struct guest_info * info,
93 struct exit_event * evt) {
94 struct exit_event * ret;
96 if ((ret = __insert_event(info, evt))) {
100 v3_rb_insert_color(&(evt->tree_node), &(info->telemetry.exit_root));
106 static struct exit_event * get_exit(struct guest_info * info, uint_t exit_code) {
107 struct rb_node * n = info->telemetry.exit_root.rb_node;
108 struct exit_event * evt = NULL;
111 evt = rb_entry(n, struct exit_event, tree_node);
113 if (exit_code < evt->exit_code) {
115 } else if (exit_code > evt->exit_code) {
126 static inline struct exit_event * create_exit(uint_t exit_code) {
127 struct exit_event * evt = V3_Malloc(sizeof(struct exit_event));
129 evt->exit_code = exit_code;
131 evt->handler_time = 0;
136 void v3_telemetry_start_exit(struct guest_info * info) {
137 rdtscll(info->telemetry.vmm_start_tsc);
141 void v3_telemetry_end_exit(struct guest_info * info, uint_t exit_code) {
142 struct v3_telemetry_state * telemetry = &(info->telemetry);
143 struct exit_event * evt = NULL;
144 uint64_t end_tsc = 0;
148 evt = get_exit(info, exit_code);
151 evt = create_exit(exit_code);
152 insert_event(info, evt);
155 evt->handler_time += end_tsc - telemetry->vmm_start_tsc;
158 telemetry->exit_cnt++;
162 // check if the exit count has expired
163 if ((telemetry->exit_cnt % telemetry->granularity) == 0) {
164 v3_print_telemetry(info);
171 void v3_add_telemetry_cb(struct guest_info * info,
172 void (*telemetry_fn)(struct guest_info * info, void * private_data, char * hdr),
173 void * private_data) {
174 struct v3_telemetry_state * telemetry = &(info->telemetry);
175 struct telemetry_cb * cb = (struct telemetry_cb *)V3_Malloc(sizeof(struct telemetry_cb));
177 cb->private_data = private_data;
178 cb->telemetry_fn = telemetry_fn;
180 list_add(&(cb->cb_node), &(telemetry->cb_list));
185 void v3_print_telemetry(struct guest_info * info) {
186 struct v3_telemetry_state * telemetry = &(info->telemetry);
187 uint64_t invoke_tsc = 0;
192 snprintf(hdr_buf, 32, "telem.%d>", telemetry->invoke_cnt++);
194 V3_Print("%stelemetry window tsc cnt: %d\n", hdr_buf, (uint32_t)(invoke_tsc - telemetry->prev_tsc));
198 struct exit_event * evt = NULL;
199 struct rb_node * node = v3_rb_first(&(info->telemetry.exit_root));
202 evt = rb_entry(node, struct exit_event, tree_node);
203 const char * code_str = vmexit_code_to_str(evt->exit_code);
205 V3_Print("%s%s:%sCnt=%u,%sAvg. Time=%u\n",
208 (strlen(code_str) > 13) ? "\t" : "\t\t",
210 (evt->cnt >= 100) ? "\t" : "\t\t",
211 (uint32_t)(evt->handler_time / evt->cnt));
212 } while ((node = v3_rb_next(node)));
216 // Registered callbacks
218 struct telemetry_cb * cb = NULL;
220 list_for_each_entry(cb, &(telemetry->cb_list), cb_node) {
221 cb->telemetry_fn(info, cb->private_data, hdr_buf);
225 telemetry->prev_tsc = invoke_tsc;
227 V3_Print("%s Telemetry done\n", hdr_buf);