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.


Partially functional icc_bus (works for UP)
[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 CONFIG_TELEMETRY_GRANULARITY
28 #define DEFAULT_GRANULARITY 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 void v3_init_telemetry(struct v3_vm_info * vm) {
54     struct v3_telemetry_state * telemetry = &(vm->telemetry);
55
56     telemetry->invoke_cnt = 0;
57     telemetry->granularity = DEFAULT_GRANULARITY;
58
59     telemetry->prev_tsc = 0;
60
61     INIT_LIST_HEAD(&(telemetry->cb_list));
62 }
63
64 void v3_init_core_telemetry(struct guest_info * core) {
65     struct v3_core_telemetry * telemetry = &(core->core_telem);
66
67     telemetry->exit_cnt = 0;
68     telemetry->vmm_start_tsc = 0;
69
70     telemetry->vm_telem = &(core->vm_info->telemetry);
71
72     telemetry->exit_root.rb_node = NULL;
73 }
74
75
76
77 static inline struct exit_event * __insert_event(struct guest_info * info, 
78                                                  struct exit_event * evt) {
79     struct rb_node ** p = &(info->core_telem.exit_root.rb_node);
80     struct rb_node * parent = NULL;
81     struct exit_event * tmp_evt = NULL;
82
83     while (*p) {
84         parent = *p;
85         tmp_evt = rb_entry(parent, struct exit_event, tree_node);
86
87         if (evt->exit_code < tmp_evt->exit_code) {
88             p = &(*p)->rb_left;
89         } else if (evt->exit_code > tmp_evt->exit_code) {
90             p = &(*p)->rb_right;
91         } else {
92             return tmp_evt;
93         }
94     }
95     rb_link_node(&(evt->tree_node), parent, p);
96
97     return NULL;
98 }
99
100 static inline struct exit_event * insert_event(struct guest_info * info, 
101                                                struct exit_event * evt) {
102     struct exit_event * ret;
103
104     if ((ret = __insert_event(info, evt))) {
105         return ret;
106     }
107
108     v3_rb_insert_color(&(evt->tree_node), &(info->core_telem.exit_root));
109
110     return NULL;
111 }
112
113
114 static struct exit_event * get_exit(struct guest_info * info, uint_t exit_code) {
115     struct rb_node * n = info->core_telem.exit_root.rb_node;
116     struct exit_event * evt = NULL;
117
118     while (n) {
119         evt = rb_entry(n, struct exit_event, tree_node);
120     
121         if (exit_code < evt->exit_code) {
122             n = n->rb_left;
123         } else if (exit_code > evt->exit_code) {
124             n = n->rb_right;
125         } else {
126             return evt;
127         }
128     }
129
130     return NULL;
131 }
132
133
134 static inline struct exit_event * create_exit(uint_t exit_code) {
135     struct exit_event * evt = V3_Malloc(sizeof(struct exit_event));
136
137     evt->exit_code = exit_code;
138     evt->cnt = 0;
139     evt->handler_time = 0;
140
141     return evt;
142 }
143
144 void v3_telemetry_start_exit(struct guest_info * info) {
145     rdtscll(info->core_telem.vmm_start_tsc);
146 }
147
148
149 void v3_telemetry_end_exit(struct guest_info * info, uint_t exit_code) {
150     struct v3_core_telemetry * telemetry = &(info->core_telem);
151     struct exit_event * evt = NULL;
152     uint64_t end_tsc = 0;
153
154     rdtscll(end_tsc);
155
156     evt = get_exit(info, exit_code);
157
158     if (evt == NULL) {
159         evt = create_exit(exit_code);
160         insert_event(info, evt);
161     }
162
163     evt->handler_time += end_tsc - telemetry->vmm_start_tsc;
164
165     evt->cnt++;
166     telemetry->exit_cnt++;
167
168
169
170     // check if the exit count has expired
171     if ((telemetry->exit_cnt % telemetry->vm_telem->granularity) == 0) {
172         v3_print_telemetry(info->vm_info);
173     }
174 }
175
176
177
178
179 void v3_add_telemetry_cb(struct v3_vm_info * vm, 
180                          void (*telemetry_fn)(struct v3_vm_info * vm, void * private_data, char * hdr),
181                          void * private_data) {
182     struct v3_telemetry_state * telemetry = &(vm->telemetry);
183     struct telemetry_cb * cb = (struct telemetry_cb *)V3_Malloc(sizeof(struct telemetry_cb));
184
185     cb->private_data = private_data;
186     cb->telemetry_fn = telemetry_fn;
187
188     list_add(&(cb->cb_node), &(telemetry->cb_list));
189 }
190
191
192
193 void v3_print_telemetry(struct v3_vm_info * vm) {
194     struct v3_telemetry_state * telemetry = &(vm->telemetry);
195     uint64_t invoke_tsc = 0;
196     char hdr_buf[32];
197     int i;
198
199     rdtscll(invoke_tsc);
200
201     snprintf(hdr_buf, 32, "telem.%d>", telemetry->invoke_cnt++);
202
203     V3_Print("%stelemetry window tsc cnt: %d\n", hdr_buf, (uint32_t)(invoke_tsc - telemetry->prev_tsc));
204
205
206     // Exit Telemetry
207     for (i = 0; i < vm->num_cores; i++) {
208         struct guest_info * core = &(vm->cores[i]);
209         struct exit_event * evt = NULL;
210         struct rb_node * node = v3_rb_first(&(core->core_telem.exit_root));
211         
212         V3_Print("Exit information for Core %d\n", core->cpu_id);
213
214         if (!node) { 
215             V3_Print("No information yet for this core\n");
216             continue;
217         }
218
219         do {
220             evt = rb_entry(node, struct exit_event, tree_node);
221             const char * code_str = vmexit_code_to_str(evt->exit_code);
222             
223             V3_Print("%s%s:%sCnt=%u,%sAvg. Time=%u\n", 
224                      hdr_buf,
225                      code_str,
226                      (strlen(code_str) > 13) ? "\t" : "\t\t",
227                      evt->cnt,
228                      (evt->cnt >= 100) ? "\t" : "\t\t",
229                      (uint32_t)(evt->handler_time / evt->cnt));
230         } while ((node = v3_rb_next(node)));
231     }
232
233
234     // Registered callbacks
235     {
236         struct telemetry_cb * cb = NULL;
237
238         list_for_each_entry(cb, &(telemetry->cb_list), cb_node) {
239             cb->telemetry_fn(vm, cb->private_data, hdr_buf);
240         }
241     }
242
243     telemetry->prev_tsc = invoke_tsc;
244
245     V3_Print("%s Telemetry done\n", hdr_buf);
246
247 }