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.


Split telemetry into global and per-core to avoid race printing core telemetry
[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_global_telemetry(info->vm_info);
208         v3_print_core_telemetry(info);
209     }
210 }
211
212
213
214
215 void v3_add_telemetry_cb(struct v3_vm_info * vm, 
216                          void (*telemetry_fn)(struct v3_vm_info * vm, void * private_data, char * hdr),
217                          void * private_data) {
218     struct v3_telemetry_state * telemetry = &(vm->telemetry);
219     struct telemetry_cb * cb = (struct telemetry_cb *)V3_Malloc(sizeof(struct telemetry_cb));
220
221     cb->private_data = private_data;
222     cb->telemetry_fn = telemetry_fn;
223
224     list_add(&(cb->cb_node), &(telemetry->cb_list));
225 }
226
227
228
229 static int free_callback(struct v3_vm_info * vm, struct telemetry_cb * cb) {
230     list_del(&(cb->cb_node));
231     V3_Free(cb);
232
233     return 0;
234 }
235
236
237 void v3_print_core_telemetry(struct guest_info * core ) {
238     struct exit_event * evt = NULL;
239     struct rb_node * node = v3_rb_first(&(core->core_telem.exit_root));
240     
241     V3_Print("Exit information for Core %d\n", core->vcpu_id);
242     
243     if (!node) { 
244         V3_Print("No information yet for this core\n");
245         return;
246     }
247
248     do {
249          evt = rb_entry(node, struct exit_event, tree_node);
250          const char * code_str = vmexit_code_to_str(evt->exit_code);
251             
252          V3_Print("%s:%sCnt=%u,%sAvg. Time=%u\n", 
253                   code_str,
254                   (strlen(code_str) > 13) ? "\t" : "\t\t",
255                   evt->cnt,
256                   (evt->cnt >= 100) ? "\t" : "\t\t",
257                   (uint32_t)(evt->handler_time / evt->cnt));
258     } while ((node = v3_rb_next(node)));
259     return;
260 }
261
262 void v3_print_global_telemetry(struct v3_vm_info * vm) {
263     struct v3_telemetry_state * telemetry = &(vm->telemetry);
264     uint64_t invoke_tsc = 0;
265     char hdr_buf[32];
266
267     rdtscll(invoke_tsc);
268
269     snprintf(hdr_buf, 32, "telem.%d>", telemetry->invoke_cnt++);
270
271     V3_Print("%stelemetry window tsc cnt: %d\n", hdr_buf, (uint32_t)(invoke_tsc - telemetry->prev_tsc));
272
273     // Registered callbacks
274     {
275         struct telemetry_cb * cb = NULL;
276
277         list_for_each_entry(cb, &(telemetry->cb_list), cb_node) {
278             cb->telemetry_fn(vm, cb->private_data, hdr_buf);
279         }
280     }
281
282     telemetry->prev_tsc = invoke_tsc;
283
284     V3_Print("%s Telemetry done\n", hdr_buf);
285 }