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.


Context-based output infrastructure (V3_Print, etc) and modifications to use it
[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     if (!evt) {
166         PrintError(VM_NONE, VCORE_NONE, "Cannot allocate in createing exit in telemetry\n");
167         return NULL;
168     }
169
170     evt->exit_code = exit_code;
171     evt->cnt = 0;
172     evt->handler_time = 0;
173
174     return evt;
175 }
176
177
178
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));
181     V3_Free(evt);
182     return 0;
183 }
184
185
186 void v3_telemetry_start_exit(struct guest_info * info) {
187     rdtscll(info->core_telem.vmm_start_tsc);
188 }
189
190
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;
195
196     rdtscll(end_tsc);
197
198     evt = get_exit(info, exit_code);
199
200     if (evt == NULL) {
201         evt = create_exit(exit_code);
202         insert_event(info, evt);
203     }
204
205     evt->handler_time += end_tsc - telemetry->vmm_start_tsc;
206
207     evt->cnt++;
208     telemetry->exit_cnt++;
209
210
211
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);
215     }
216 }
217
218
219
220
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));
226
227     if (!cb) {
228         PrintError(vm, VCORE_NONE, "Cannot allocate in adding a telemtry callback\n");
229         return ;
230     }
231
232     cb->private_data = private_data;
233     cb->telemetry_fn = telemetry_fn;
234
235     list_add(&(cb->cb_node), &(telemetry->cb_list));
236 }
237
238
239
240 static int free_callback(struct v3_vm_info * vm, struct telemetry_cb * cb) {
241     list_del(&(cb->cb_node));
242     V3_Free(cb);
243
244     return 0;
245 }
246
247
248 static void telemetry_header(struct v3_vm_info *vm, char *hdr_buf, int len)
249 {
250     struct v3_telemetry_state * telemetry = &(vm->telemetry);
251     snprintf(hdr_buf, len, "telem.%d>", telemetry->invoke_cnt);
252 }
253
254 static void print_telemetry_start(struct v3_vm_info *vm, char *hdr_buf)
255 {
256     struct v3_telemetry_state * telemetry = &(vm->telemetry);
257     uint64_t invoke_tsc = 0;
258     rdtscll(invoke_tsc);
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;
261 }
262
263 static void print_telemetry_end(struct v3_vm_info *vm, char *hdr_buf)
264 {
265     V3_Print(vm, VCORE_NONE, "%s Telemetry done\n", hdr_buf);
266 }
267
268 static void print_core_telemetry(struct guest_info * core, char *hdr_buf)
269 {
270     struct exit_event * evt = NULL;
271     struct rb_node * node = v3_rb_first(&(core->core_telem.exit_root));
272
273     V3_Print(core->vm_info, core, "Exit information for Core %d\n", core->vcpu_id);
274     
275     if (!node) { 
276         V3_Print(core->vm_info, core, "No information yet for this core\n");
277         return;
278     }
279
280     do {
281         extern v3_cpu_arch_t v3_mach_type;
282         const char * code_str = NULL;
283         
284         evt = rb_entry(node, struct exit_event, tree_node);
285
286         switch (v3_mach_type) {
287             case V3_SVM_CPU:
288             case V3_SVM_REV3_CPU:
289                 
290                 code_str = v3_svm_exit_code_to_str(evt->exit_code);
291                 break;
292             case V3_VMX_CPU:
293             case V3_VMX_EPT_CPU:
294             case V3_VMX_EPT_UG_CPU:
295                 code_str = v3_vmx_exit_code_to_str(evt->exit_code);
296                 break;
297
298             default:
299                 continue;
300         }
301
302         V3_Print(core->vm_info, core, "%s%s:%sCnt=%u,%sAvg. Time=%u\n", 
303                  hdr_buf, code_str,
304                  (strlen(code_str) > 13) ? "\t" : "\t\t",
305                  evt->cnt,
306                  (evt->cnt >= 100) ? "\t" : "\t\t",
307                  (uint32_t)(evt->handler_time / evt->cnt));
308     } while ((node = v3_rb_next(node)));
309     return;
310 }
311
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);
315     char hdr_buf[32];
316     
317     telemetry_header(vm, hdr_buf, 32);
318     telemetry->invoke_cnt++; // XXX this increment isn't atomic and probably should be
319
320     print_telemetry_start(vm, hdr_buf);
321     print_core_telemetry(core, hdr_buf);
322     print_telemetry_end(vm, hdr_buf);
323
324     return;
325 }
326
327 static void telemetry_callbacks(struct v3_vm_info * vm, char *hdr_buf)
328 {
329     struct v3_telemetry_state * telemetry = &(vm->telemetry);
330     // Registered callbacks
331     {
332         struct telemetry_cb * cb = NULL;
333
334         list_for_each_entry(cb, &(telemetry->cb_list), cb_node) {
335             cb->telemetry_fn(vm, cb->private_data, hdr_buf);
336         }
337     }
338 }
339
340 void v3_print_global_telemetry(struct v3_vm_info * vm) {
341     struct v3_telemetry_state * telemetry = &(vm->telemetry);
342     char hdr_buf[32];
343
344     telemetry_header(vm, hdr_buf, 32);
345     telemetry->invoke_cnt++; // XXX this increment isn't atomic and probably should be
346
347     print_telemetry_start( vm, hdr_buf );
348     telemetry_callbacks( vm, hdr_buf );
349     print_telemetry_end( vm, hdr_buf );
350 }
351
352 void v3_print_telemetry(struct v3_vm_info * vm, struct guest_info * core )
353 {
354     struct v3_telemetry_state * telemetry = &(vm->telemetry);
355     char hdr_buf[32];
356     
357     telemetry_header(vm, hdr_buf, 32);
358     telemetry->invoke_cnt++; // XXX this increment isn't atomic and probably should be
359
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);
364
365     return;
366 }