Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


c0eb38d3cdb1c3b0506adeb72fddf68a4205073e
[palacios.git] / palacios / src / palacios / vmm_telemetry.c
1 /*
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.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
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.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
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>
26
27
28
29 #ifdef V3_CONFIG_TELEMETRY_GRANULARITY
30 #define DEFAULT_GRANULARITY V3_CONFIG_TELEMETRY_GRANULARITY
31 #else 
32 #define DEFAULT_GRANULARITY 50000
33 #endif
34
35
36
37 struct telemetry_cb {
38     
39     void (*telemetry_fn)(struct v3_vm_info * vm, void * private_data, char * hdr);
40
41     void * private_data;
42     struct list_head cb_node;
43 };
44
45
46 struct exit_event {
47     uint_t exit_code;
48     uint_t cnt;
49     uint64_t handler_time;
50
51     struct rb_node tree_node;
52 };
53
54
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);
57
58
59 void v3_init_telemetry(struct v3_vm_info * vm) {
60     struct v3_telemetry_state * telemetry = &(vm->telemetry);
61
62     telemetry->invoke_cnt = 0;
63     telemetry->granularity = DEFAULT_GRANULARITY;
64
65     telemetry->prev_tsc = 0;
66
67     INIT_LIST_HEAD(&(telemetry->cb_list));
68 }
69
70 void v3_deinit_telemetry(struct v3_vm_info * vm) {
71     struct telemetry_cb * cb = NULL;
72     struct telemetry_cb * tmp = NULL;
73
74     list_for_each_entry_safe(cb, tmp, &(vm->telemetry.cb_list), cb_node) {
75         free_callback(vm, cb);
76     }
77 }
78
79
80 void v3_init_core_telemetry(struct guest_info * core) {
81     struct v3_core_telemetry * telemetry = &(core->core_telem);
82
83     telemetry->exit_cnt = 0;
84     telemetry->vmm_start_tsc = 0;
85
86     telemetry->vm_telem = &(core->vm_info->telemetry);
87
88     telemetry->exit_root.rb_node = NULL;
89 }
90
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;
94
95     while (node) {
96         evt = rb_entry(node, struct exit_event, tree_node);
97         node = v3_rb_next(node);
98
99         free_exit(core, evt);
100     }
101 }
102
103
104
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;
110
111     while (*p) {
112         parent = *p;
113         tmp_evt = rb_entry(parent, struct exit_event, tree_node);
114
115         if (evt->exit_code < tmp_evt->exit_code) {
116             p = &(*p)->rb_left;
117         } else if (evt->exit_code > tmp_evt->exit_code) {
118             p = &(*p)->rb_right;
119         } else {
120             return tmp_evt;
121         }
122     }
123     rb_link_node(&(evt->tree_node), parent, p);
124
125     return NULL;
126 }
127
128 static inline struct exit_event * insert_event(struct guest_info * info, 
129                                                struct exit_event * evt) {
130     struct exit_event * ret;
131
132     if ((ret = __insert_event(info, evt))) {
133         return ret;
134     }
135
136     v3_rb_insert_color(&(evt->tree_node), &(info->core_telem.exit_root));
137
138     return NULL;
139 }
140
141
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;
145
146     while (n) {
147         evt = rb_entry(n, struct exit_event, tree_node);
148     
149         if (exit_code < evt->exit_code) {
150             n = n->rb_left;
151         } else if (exit_code > evt->exit_code) {
152             n = n->rb_right;
153         } else {
154             return evt;
155         }
156     }
157
158     return NULL;
159 }
160
161
162 static inline struct exit_event * create_exit(uint_t exit_code) {
163     struct exit_event * evt = V3_Malloc(sizeof(struct exit_event));
164
165     evt->exit_code = exit_code;
166     evt->cnt = 0;
167     evt->handler_time = 0;
168
169     return evt;
170 }
171
172
173
174 static int free_exit(struct guest_info * core, struct exit_event * evt) {
175     v3_rb_erase(&(evt->tree_node), &(core->core_telem.exit_root));
176     V3_Free(evt);
177     return 0;
178 }
179
180
181 void v3_telemetry_start_exit(struct guest_info * info) {
182     rdtscll(info->core_telem.vmm_start_tsc);
183 }
184
185
186 void v3_telemetry_end_exit(struct guest_info * info, uint_t exit_code) {
187     struct v3_core_telemetry * telemetry = &(info->core_telem);
188     struct exit_event * evt = NULL;
189     uint64_t end_tsc = 0;
190
191     rdtscll(end_tsc);
192
193     evt = get_exit(info, exit_code);
194
195     if (evt == NULL) {
196         evt = create_exit(exit_code);
197         insert_event(info, evt);
198     }
199
200     evt->handler_time += end_tsc - telemetry->vmm_start_tsc;
201
202     evt->cnt++;
203     telemetry->exit_cnt++;
204
205
206
207     // check if the exit count has expired
208     if ((telemetry->exit_cnt % telemetry->vm_telem->granularity) == 0) {
209         v3_print_telemetry(info->vm_info, info);
210     }
211 }
212
213
214
215
216 void v3_add_telemetry_cb(struct v3_vm_info * vm, 
217                          void (*telemetry_fn)(struct v3_vm_info * vm, void * private_data, char * hdr),
218                          void * private_data) {
219     struct v3_telemetry_state * telemetry = &(vm->telemetry);
220     struct telemetry_cb * cb = (struct telemetry_cb *)V3_Malloc(sizeof(struct telemetry_cb));
221
222     cb->private_data = private_data;
223     cb->telemetry_fn = telemetry_fn;
224
225     list_add(&(cb->cb_node), &(telemetry->cb_list));
226 }
227
228
229
230 static int free_callback(struct v3_vm_info * vm, struct telemetry_cb * cb) {
231     list_del(&(cb->cb_node));
232     V3_Free(cb);
233
234     return 0;
235 }
236
237
238 static void telemetry_header(struct v3_vm_info *vm, char *hdr_buf, int len)
239 {
240     struct v3_telemetry_state * telemetry = &(vm->telemetry);
241     snprintf(hdr_buf, len, "telem.%d>", telemetry->invoke_cnt);
242 }
243
244 static void print_telemetry_start(struct v3_vm_info *vm, char *hdr_buf)
245 {
246     struct v3_telemetry_state * telemetry = &(vm->telemetry);
247     uint64_t invoke_tsc = 0;
248     rdtscll(invoke_tsc);
249     V3_Print("%stelemetry window tsc cnt: %d\n", hdr_buf, (uint32_t)(invoke_tsc - telemetry->prev_tsc));
250     telemetry->prev_tsc = invoke_tsc;
251 }
252
253 static void print_telemetry_end(struct v3_vm_info *vm, char *hdr_buf)
254 {
255     V3_Print("%s Telemetry done\n", hdr_buf);
256 }
257
258 static void print_core_telemetry(struct guest_info * core, char *hdr_buf)
259 {
260     struct exit_event * evt = NULL;
261     struct rb_node * node = v3_rb_first(&(core->core_telem.exit_root));
262
263     V3_Print("Exit information for Core %d\n", core->vcpu_id);
264     
265     if (!node) { 
266         V3_Print("No information yet for this core\n");
267         return;
268     }
269
270     do {
271         extern v3_cpu_arch_t v3_mach_type;
272         const char * code_str = NULL;
273         
274         evt = rb_entry(node, struct exit_event, tree_node);
275
276         switch (v3_mach_type) {
277             case V3_SVM_CPU:
278             case V3_SVM_REV3_CPU:
279                 
280                 code_str = v3_svm_exit_code_to_str(evt->exit_code);
281                 break;
282             case V3_VMX_CPU:
283             case V3_VMX_EPT_CPU:
284             case V3_VMX_EPT_UG_CPU:
285                 code_str = v3_vmx_exit_code_to_str(evt->exit_code);
286                 break;
287
288             default:
289                 continue;
290         }
291
292         V3_Print("%s%s:%sCnt=%u,%sAvg. Time=%u\n", 
293                  hdr_buf, code_str,
294                  (strlen(code_str) > 13) ? "\t" : "\t\t",
295                  evt->cnt,
296                  (evt->cnt >= 100) ? "\t" : "\t\t",
297                  (uint32_t)(evt->handler_time / evt->cnt));
298     } while ((node = v3_rb_next(node)));
299     return;
300 }
301
302 void v3_print_core_telemetry(struct guest_info * core ) {
303     struct v3_vm_info *vm = core->vm_info;
304     struct v3_telemetry_state * telemetry = &(vm->telemetry);
305     char hdr_buf[32];
306     
307     telemetry_header(vm, hdr_buf, 32);
308     telemetry->invoke_cnt++; // XXX this increment isn't atomic and probably should be
309
310     print_telemetry_start(vm, hdr_buf);
311     print_core_telemetry(core, hdr_buf);
312     print_telemetry_end(vm, hdr_buf);
313
314     return;
315 }
316
317 static void telemetry_callbacks(struct v3_vm_info * vm, char *hdr_buf)
318 {
319     struct v3_telemetry_state * telemetry = &(vm->telemetry);
320     // Registered callbacks
321     {
322         struct telemetry_cb * cb = NULL;
323
324         list_for_each_entry(cb, &(telemetry->cb_list), cb_node) {
325             cb->telemetry_fn(vm, cb->private_data, hdr_buf);
326         }
327     }
328 }
329
330 void v3_print_global_telemetry(struct v3_vm_info * vm) {
331     struct v3_telemetry_state * telemetry = &(vm->telemetry);
332     char hdr_buf[32];
333
334     telemetry_header(vm, hdr_buf, 32);
335     telemetry->invoke_cnt++; // XXX this increment isn't atomic and probably should be
336
337     print_telemetry_start( vm, hdr_buf );
338     telemetry_callbacks( vm, hdr_buf );
339     print_telemetry_end( vm, hdr_buf );
340 }
341
342 void v3_print_telemetry(struct v3_vm_info * vm, struct guest_info * core )
343 {
344     struct v3_telemetry_state * telemetry = &(vm->telemetry);
345     char hdr_buf[32];
346     
347     telemetry_header(vm, hdr_buf, 32);
348     telemetry->invoke_cnt++; // XXX this increment isn't atomic and probably should be
349
350     print_telemetry_start(vm, hdr_buf);
351     print_core_telemetry(core, hdr_buf);
352     telemetry_callbacks(vm, hdr_buf);
353     print_telemetry_end(vm, hdr_buf);
354
355     return;
356 }