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>
26 #ifdef CONFIG_TELEMETRY_GRANULARITY
27 #define DEFAULT_GRANULARITY CONFIG_TELEMETRY_GRANULARITY
29 #define DEFAULT_GRANULARITY 20000
36 void (*telemetry_fn)(struct guest_info * info, void * private_data);
39 struct list_head cb_node;
46 uint64_t handler_time;
48 struct rb_node tree_node;
52 void v3_init_telemetry(struct guest_info * info) {
53 struct v3_telemetry_state * telemetry = &(info->telemetry);
55 telemetry->exit_cnt = 0;
56 telemetry->vmm_start_tsc = 0;
57 telemetry->prev_tsc = 0;
58 telemetry->invoke_cnt = 0;
59 telemetry->granularity = DEFAULT_GRANULARITY;
62 telemetry->exit_root.rb_node = NULL;
63 INIT_LIST_HEAD(&(telemetry->cb_list));
68 static inline struct exit_event * __insert_event(struct guest_info * info,
69 struct exit_event * evt) {
70 struct rb_node ** p = &(info->telemetry.exit_root.rb_node);
71 struct rb_node * parent = NULL;
72 struct exit_event * tmp_evt = NULL;
76 tmp_evt = rb_entry(parent, struct exit_event, tree_node);
78 if (evt->exit_code < tmp_evt->exit_code) {
80 } else if (evt->exit_code > tmp_evt->exit_code) {
86 rb_link_node(&(evt->tree_node), parent, p);
91 static inline struct exit_event * insert_event(struct guest_info * info,
92 struct exit_event * evt) {
93 struct exit_event * ret;
95 if ((ret = __insert_event(info, evt))) {
99 v3_rb_insert_color(&(evt->tree_node), &(info->telemetry.exit_root));
105 static struct exit_event * get_exit(struct guest_info * info, uint_t exit_code) {
106 struct rb_node * n = info->telemetry.exit_root.rb_node;
107 struct exit_event * evt = NULL;
110 evt = rb_entry(n, struct exit_event, tree_node);
112 if (exit_code < evt->exit_code) {
114 } else if (exit_code > evt->exit_code) {
125 static inline struct exit_event * create_exit(uint_t exit_code) {
126 struct exit_event * evt = V3_Malloc(sizeof(struct exit_event));
128 evt->exit_code = exit_code;
130 evt->handler_time = 0;
135 void v3_telemetry_start_exit(struct guest_info * info) {
136 rdtscll(info->telemetry.vmm_start_tsc);
140 void v3_telemetry_end_exit(struct guest_info * info, uint_t exit_code) {
141 struct v3_telemetry_state * telemetry = &(info->telemetry);
142 struct exit_event * evt = NULL;
143 uint64_t end_tsc = 0;
147 evt = get_exit(info, exit_code);
150 evt = create_exit(exit_code);
151 insert_event(info, evt);
154 evt->handler_time += end_tsc - telemetry->vmm_start_tsc;
157 telemetry->exit_cnt++;
161 // check if the exit count has expired
162 if ((telemetry->exit_cnt % telemetry->granularity) == 0) {
163 v3_print_telemetry(info);
170 void v3_add_telemetry_cb(struct guest_info * info,
171 void (*telemetry_fn)(struct guest_info * info, void * private_data),
172 void * private_data) {
173 struct v3_telemetry_state * telemetry = &(info->telemetry);
174 struct telemetry_cb * cb = (struct telemetry_cb *)V3_Malloc(sizeof(struct telemetry_cb));
176 cb->private_data = private_data;
177 cb->telemetry_fn = telemetry_fn;
179 list_add(&(cb->cb_node), &(telemetry->cb_list));
183 void v3_print_telemetry(struct guest_info * info) {
184 struct v3_telemetry_state * telemetry = &(info->telemetry);
185 uint64_t invoke_tsc = 0;
189 V3_Print("Telemetry (%d)\n", telemetry->invoke_cnt++);
190 V3_Print("\ttelemetry window tsc cnt: %d\n", (uint32_t)(invoke_tsc - telemetry->prev_tsc));
194 struct exit_event * evt = NULL;
195 struct rb_node * node = v3_rb_first(&(info->telemetry.exit_root));
198 evt = rb_entry(node, struct exit_event, tree_node);
199 const char * code_str = vmexit_code_to_str(evt->exit_code);
201 V3_Print("%s:%sCnt=%u,%sAvg. Time=%u\n",
203 (strlen(code_str) > 14) ? "\t" : "\t\t",
205 (evt->cnt >= 100) ? "\t" : "\t\t",
206 (uint32_t)(evt->handler_time / evt->cnt));
208 } while ((node = v3_rb_next(node)));
212 // Registered callbacks
214 struct telemetry_cb * cb = NULL;
216 list_for_each_entry(cb, &(telemetry->cb_list), cb_node) {
217 cb->telemetry_fn(info, cb->private_data);
221 telemetry->prev_tsc = invoke_tsc;