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.


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