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.


bug fix to check for illegal memory ranges
[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/vmm_rbtree.h>
24 #include <palacios/vmm_sprintf.h>
25
26
27 #ifdef V3_CONFIG_TELEMETRY_GRANULARITY
28 #define DEFAULT_GRANULARITY V3_CONFIG_TELEMETRY_GRANULARITY
29 #else 
30 #define DEFAULT_GRANULARITY 50000
31 #endif
32
33
34
35 struct telemetry_cb {
36     
37     void (*telemetry_fn)(struct v3_vm_info * vm, void * private_data, char * hdr);
38
39     void * private_data;
40     struct list_head cb_node;
41 };
42
43
44 struct exit_event {
45     uint_t exit_code;
46     uint_t cnt;
47     uint64_t handler_time;
48
49     struct rb_node tree_node;
50 };
51
52
53 static int free_callback(struct v3_vm_info * vm, struct telemetry_cb * cb);
54 static int free_exit(struct guest_info * core, struct exit_event * event);
55
56
57 void v3_init_telemetry(struct v3_vm_info * vm) {
58     struct v3_telemetry_state * telemetry = &(vm->telemetry);
59
60     telemetry->invoke_cnt = 0;
61     telemetry->granularity = DEFAULT_GRANULARITY;
62
63     telemetry->prev_tsc = 0;
64
65     INIT_LIST_HEAD(&(telemetry->cb_list));
66 }
67
68 void v3_deinit_telemetry(struct v3_vm_info * vm) {
69     struct telemetry_cb * cb = NULL;
70     struct telemetry_cb * tmp = NULL;
71
72     list_for_each_entry_safe(cb, tmp, &(vm->telemetry.cb_list), cb_node) {
73         free_callback(vm, cb);
74     }
75 }
76
77
78 void v3_init_core_telemetry(struct guest_info * core) {
79     struct v3_core_telemetry * telemetry = &(core->core_telem);
80
81     telemetry->exit_cnt = 0;
82     telemetry->vmm_start_tsc = 0;
83
84     telemetry->vm_telem = &(core->vm_info->telemetry);
85
86     telemetry->exit_root.rb_node = NULL;
87 }
88
89 void v3_deinit_core_telemetry(struct guest_info * core) {
90     struct rb_node * node = v3_rb_first(&(core->core_telem.exit_root));
91     struct exit_event * evt = NULL;
92
93     while (node) {
94         evt = rb_entry(node, struct exit_event, tree_node);
95         node = v3_rb_next(node);
96
97         free_exit(core, evt);
98     }
99 }
100
101
102
103 static inline struct exit_event * __insert_event(struct guest_info * info, 
104                                                  struct exit_event * evt) {
105     struct rb_node ** p = &(info->core_telem.exit_root.rb_node);
106     struct rb_node * parent = NULL;
107     struct exit_event * tmp_evt = NULL;
108
109     while (*p) {
110         parent = *p;
111         tmp_evt = rb_entry(parent, struct exit_event, tree_node);
112
113         if (evt->exit_code < tmp_evt->exit_code) {
114             p = &(*p)->rb_left;
115         } else if (evt->exit_code > tmp_evt->exit_code) {
116             p = &(*p)->rb_right;
117         } else {
118             return tmp_evt;
119         }
120     }
121     rb_link_node(&(evt->tree_node), parent, p);
122
123     return NULL;
124 }
125
126 static inline struct exit_event * insert_event(struct guest_info * info, 
127                                                struct exit_event * evt) {
128     struct exit_event * ret;
129
130     if ((ret = __insert_event(info, evt))) {
131         return ret;
132     }
133
134     v3_rb_insert_color(&(evt->tree_node), &(info->core_telem.exit_root));
135
136     return NULL;
137 }
138
139
140 static struct exit_event * get_exit(struct guest_info * info, uint_t exit_code) {
141     struct rb_node * n = info->core_telem.exit_root.rb_node;
142     struct exit_event * evt = NULL;
143
144     while (n) {
145         evt = rb_entry(n, struct exit_event, tree_node);
146     
147         if (exit_code < evt->exit_code) {
148             n = n->rb_left;
149         } else if (exit_code > evt->exit_code) {
150             n = n->rb_right;
151         } else {
152             return evt;
153         }
154     }
155
156     return NULL;
157 }
158
159
160 static inline struct exit_event * create_exit(uint_t exit_code) {
161     struct exit_event * evt = V3_Malloc(sizeof(struct exit_event));
162
163     evt->exit_code = exit_code;
164     evt->cnt = 0;
165     evt->handler_time = 0;
166
167     return evt;
168 }
169
170
171
172 static int free_exit(struct guest_info * core, struct exit_event * evt) {
173     v3_rb_erase(&(evt->tree_node), &(core->core_telem.exit_root));
174     V3_Free(evt);
175     return 0;
176 }
177
178
179 void v3_telemetry_start_exit(struct guest_info * info) {
180     rdtscll(info->core_telem.vmm_start_tsc);
181 }
182
183
184 void v3_telemetry_end_exit(struct guest_info * info, uint_t exit_code) {
185     struct v3_core_telemetry * telemetry = &(info->core_telem);
186     struct exit_event * evt = NULL;
187     uint64_t end_tsc = 0;
188
189     rdtscll(end_tsc);
190
191     evt = get_exit(info, exit_code);
192
193     if (evt == NULL) {
194         evt = create_exit(exit_code);
195         insert_event(info, evt);
196     }
197
198     evt->handler_time += end_tsc - telemetry->vmm_start_tsc;
199
200     evt->cnt++;
201     telemetry->exit_cnt++;
202
203
204
205     // check if the exit count has expired
206     if ((telemetry->exit_cnt % telemetry->vm_telem->granularity) == 0) {
207         v3_print_telemetry(info->vm_info, info);
208     }
209 }
210
211
212
213
214 void v3_add_telemetry_cb(struct v3_vm_info * vm, 
215                          void (*telemetry_fn)(struct v3_vm_info * vm, void * private_data, char * hdr),
216                          void * private_data) {
217     struct v3_telemetry_state * telemetry = &(vm->telemetry);
218     struct telemetry_cb * cb = (struct telemetry_cb *)V3_Malloc(sizeof(struct telemetry_cb));
219
220     cb->private_data = private_data;
221     cb->telemetry_fn = telemetry_fn;
222
223     list_add(&(cb->cb_node), &(telemetry->cb_list));
224 }
225
226
227
228 static int free_callback(struct v3_vm_info * vm, struct telemetry_cb * cb) {
229     list_del(&(cb->cb_node));
230     V3_Free(cb);
231
232     return 0;
233 }
234
235
236 static void telemetry_header(struct v3_vm_info *vm, char *hdr_buf, int len)
237 {
238     struct v3_telemetry_state * telemetry = &(vm->telemetry);
239     snprintf(hdr_buf, len, "telem.%d>", telemetry->invoke_cnt);
240 }
241
242 static void print_telemetry_start(struct v3_vm_info *vm, char *hdr_buf)
243 {
244     struct v3_telemetry_state * telemetry = &(vm->telemetry);
245     uint64_t invoke_tsc = 0;
246     rdtscll(invoke_tsc);
247     V3_Print("%stelemetry window tsc cnt: %d\n", hdr_buf, (uint32_t)(invoke_tsc - telemetry->prev_tsc));
248     telemetry->prev_tsc = invoke_tsc;
249 }
250
251 static void print_telemetry_end(struct v3_vm_info *vm, char *hdr_buf)
252 {
253     V3_Print("%s Telemetry done\n", hdr_buf);
254 }
255
256 static void print_core_telemetry(struct guest_info * core, char *hdr_buf)
257 {
258     struct exit_event * evt = NULL;
259     struct rb_node * node = v3_rb_first(&(core->core_telem.exit_root));
260
261     V3_Print("Exit information for Core %d\n", core->vcpu_id);
262     
263     if (!node) { 
264         V3_Print("No information yet for this core\n");
265         return;
266     }
267
268     do {
269          evt = rb_entry(node, struct exit_event, tree_node);
270          const char * code_str = vmexit_code_to_str(evt->exit_code);
271             
272          V3_Print("%s%s:%sCnt=%u,%sAvg. Time=%u\n", 
273                   hdr_buf, code_str,
274                   (strlen(code_str) > 13) ? "\t" : "\t\t",
275                   evt->cnt,
276                   (evt->cnt >= 100) ? "\t" : "\t\t",
277                   (uint32_t)(evt->handler_time / evt->cnt));
278     } while ((node = v3_rb_next(node)));
279     return;
280 }
281
282 void v3_print_core_telemetry(struct guest_info * core ) {
283     struct v3_vm_info *vm = core->vm_info;
284     struct v3_telemetry_state * telemetry = &(vm->telemetry);
285     char hdr_buf[32];
286     
287     telemetry_header(vm, hdr_buf, 32);
288     telemetry->invoke_cnt++; // XXX this increment isn't atomic and probably should be
289
290     print_telemetry_start(vm, hdr_buf);
291     print_core_telemetry(core, hdr_buf);
292     print_telemetry_end(vm, hdr_buf);
293
294     return;
295 }
296
297 static void telemetry_callbacks(struct v3_vm_info * vm, char *hdr_buf)
298 {
299     struct v3_telemetry_state * telemetry = &(vm->telemetry);
300     // Registered callbacks
301     {
302         struct telemetry_cb * cb = NULL;
303
304         list_for_each_entry(cb, &(telemetry->cb_list), cb_node) {
305             cb->telemetry_fn(vm, cb->private_data, hdr_buf);
306         }
307     }
308 }
309
310 void v3_print_global_telemetry(struct v3_vm_info * vm) {
311     struct v3_telemetry_state * telemetry = &(vm->telemetry);
312     char hdr_buf[32];
313
314     telemetry_header(vm, hdr_buf, 32);
315     telemetry->invoke_cnt++; // XXX this increment isn't atomic and probably should be
316
317     print_telemetry_start( vm, hdr_buf );
318     telemetry_callbacks( vm, hdr_buf );
319     print_telemetry_end( vm, hdr_buf );
320 }
321
322 void v3_print_telemetry(struct v3_vm_info * vm, struct guest_info * core )
323 {
324     struct v3_telemetry_state * telemetry = &(vm->telemetry);
325     char hdr_buf[32];
326     
327     telemetry_header(vm, hdr_buf, 32);
328     telemetry->invoke_cnt++; // XXX this increment isn't atomic and probably should be
329
330     print_telemetry_start(vm, hdr_buf);
331     print_core_telemetry(core, hdr_buf);
332     telemetry_callbacks(vm, hdr_buf);
333     print_telemetry_end(vm, hdr_buf);
334
335     return;
336 }