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.


Removed spurious print
[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);
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 void v3_print_telemetry(struct v3_vm_info * vm) {
237     struct v3_telemetry_state * telemetry = &(vm->telemetry);
238     uint64_t invoke_tsc = 0;
239     char hdr_buf[32];
240     int i;
241
242     rdtscll(invoke_tsc);
243
244     snprintf(hdr_buf, 32, "telem.%d>", telemetry->invoke_cnt++);
245
246     V3_Print("%stelemetry window tsc cnt: %d\n", hdr_buf, (uint32_t)(invoke_tsc - telemetry->prev_tsc));
247
248
249     // Exit Telemetry
250     for (i = 0; i < vm->num_cores; i++) {
251         struct guest_info * core = &(vm->cores[i]);
252         struct exit_event * evt = NULL;
253         struct rb_node * node = v3_rb_first(&(core->core_telem.exit_root));
254         
255         V3_Print("Exit information for Core %d\n", core->vcpu_id);
256
257         if (!node) { 
258             V3_Print("No information yet for this core\n");
259             continue;
260         }
261
262         do {
263             evt = rb_entry(node, struct exit_event, tree_node);
264             const char * code_str = vmexit_code_to_str(evt->exit_code);
265             
266             V3_Print("%s%s:%sCnt=%u,%sAvg. Time=%u\n", 
267                      hdr_buf,
268                      code_str,
269                      (strlen(code_str) > 13) ? "\t" : "\t\t",
270                      evt->cnt,
271                      (evt->cnt >= 100) ? "\t" : "\t\t",
272                      (uint32_t)(evt->handler_time / evt->cnt));
273         } while ((node = v3_rb_next(node)));
274     }
275
276
277     // Registered callbacks
278     {
279         struct telemetry_cb * cb = NULL;
280
281         list_for_each_entry(cb, &(telemetry->cb_list), cb_node) {
282             cb->telemetry_fn(vm, cb->private_data, hdr_buf);
283         }
284     }
285
286     telemetry->prev_tsc = invoke_tsc;
287
288     V3_Print("%s Telemetry done\n", hdr_buf);
289
290 }