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.


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