vm_config.rombios_size = rombios->length;
     
     region_start += rombios->length;
+
+    vm_config.enable_profiling = 1;
     
     vm_config.vgabios = region_start;
     vm_config.vgabios_size = vgabios->length;
 
        palacios/vmm_socket.o \
        palacios/vmm_xed.o \
        palacios/vmm_rbtree.o \
+       palacios/vmm_profiler.o \
 
 #              vmx.c vmcs_gen.c vmcs.c
 
 
 
 
 int v3_handle_svm_exit(struct guest_info * info);
+const uchar_t * vmexit_code_to_str(uint_t exit_code);
+
 
 #endif // ! __V3VEE__
 
 
 #include <palacios/vmm_emulator.h>
 #include <palacios/vmm_host_events.h>
 #include <palacios/vmm_msr.h>
+#include <palacios/vmm_profiler.h>
 
 
 
 };
 
 struct shadow_page_state;
-struct shadow_map;
-struct vmm_io_map;
 struct emulation_state;
 struct v3_intr_state;
-
+struct v3_profiler;
 
 
 
   void * vmm_data;
 
 
+  uint_t enable_profiler;
+  struct v3_profiler profiler;
+
   void * decoder_state;
 
   struct v3_msr guest_efer;
 
                           // so we can specify maximum physical address size
                           // (We're screwed if we want to do 32 bit host/64 bit guest)
 
+
+  int enable_profiling;
+
   int use_ramdisk;
   void * ramdisk;
   int ramdisk_size;
 
-
 /*
  * This file is part of the Palacios Virtual Machine Monitor developed
  * by the V3VEE Project with funding from the United States National 
 
 
 
 #define DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype)            \
-  int fnname (struct hashtable * htable, keytype key, valuetype value) { \
-    return hashtable_insert(htable, (addr_t)key, (addr_t)value);               \
+  static int fnname (struct hashtable * htable, keytype key, valuetype value) { \
+    return hashtable_insert(htable, (addr_t)key, (addr_t)value);       \
   }
 
 #define DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype)            \
-  valuetype * fnname (struct hashtable * htable, keytype  key) {       \
-    return (valuetype *) (hashtable_search(htable, (addr_t)key));              \
+  static valuetype * fnname (struct hashtable * htable, keytype  key) {        \
+    return (valuetype *) (hashtable_search(htable, (addr_t)key));      \
   }
 
 #define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype, free_key)  \
-  valuetype * fnname (struct hashtable * htable, keytype key) {        \
-    return (valuetype *) (hashtable_remove(htable, (addr_t)key, free_key));    \
+  static valuetype * fnname (struct hashtable * htable, keytype key) { \
+    return (valuetype *) (hashtable_remove(htable, (addr_t)key, free_key)); \
   }
 
 
 
 uint_t hashtable_count(struct hashtable * htable);
 
+// Specialty functions for a counting hashtable 
+int hashtable_inc(struct hashtable * htable, addr_t key, addr_t value);
+int hashtable_dec(struct hashtable * htable, addr_t key, addr_t value);
+
+
   /* ************ */
  /* ITERATOR API */
 /* ************ */
 
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National 
+ * Science Foundation and the Department of Energy.  
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico.  You can find out more at 
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
 #include <palacios/vmm_types.h>
 
 
 
--- /dev/null
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National 
+ * Science Foundation and the Department of Energy.  
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico.  You can find out more at 
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#ifndef __VMM_PROFILER_H__
+#define __VMM_PROFILER_H__
+
+#ifdef __V3VEE__
+
+#include <palacios/vmm_rbtree.h>
+
+struct guest_info;
+
+
+struct v3_profiler {
+  uint_t total_exits;
+
+  ullong_t start_time;
+  ullong_t end_time;
+
+  struct rb_root root;
+};
+
+
+void v3_init_profiler(struct guest_info * info);
+
+void v3_profile_exit(struct guest_info * info, uint_t exit_code);
+
+void v3_print_profile(struct guest_info * info);
+
+
+#endif
+
+#endif
 
 
 #include <palacios/vmm_rbtree.h>
 
+#include <palacios/vmm_profiler.h>
+
 
 extern void v3_stgi();
 extern void v3_clgi();
     ullong_t tmp_tsc;
     uint_t vm_cr_low = 0, vm_cr_high = 0;
 
-
     v3_enable_ints();
     v3_clgi();
 
     v3_stgi();
 
 
-    if (num_exits % 25 == 0) {
+    if ((num_exits % 1000) == 0) {
       PrintDebug("SVM Exit number %d\n", num_exits);
+      v3_print_profile(info);
     }
 
+
      
     if (v3_handle_svm_exit(info) != 0) {
       vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
       }
       v3_print_GPRs(info);
 
-
-      
-
-
       PrintDebug("SVM Exit Code: %p\n", (void *)(addr_t)guest_ctrl->exit_code); 
       
       PrintDebug("exit_info1 low = 0x%.8x\n", *(uint_t*)&(guest_ctrl->exit_info1));
 
       break;
     }
+
   }
   return 0;
 }
 
 #include <palacios/vmm_intr.h>
 #include <palacios/vmm_emulator.h>
 #include <palacios/svm_msr.h>
+#include <palacios/vmm_profiler.h>
 
 
 
-static const uchar_t * vmexit_code_to_str(uint_t exit_code);
-
 
 int v3_handle_svm_exit(struct guest_info * info) {
   vmcb_ctrl_t * guest_ctrl = 0;
 
 
   exit_code = guest_ctrl->exit_code;
- 
+
+
+
+  
 
   // Disable printing io exits due to bochs debug messages
   //if (!((exit_code == VMEXIT_IOIO) && ((ushort_t)(guest_ctrl->exit_info1 >> 16) == 0x402))) {
   }
 
 
-    //  }
-  // PrintDebugVMCB((vmcb_t*)(info->vmm_data));
-
 
-  // PrintDebug("SVM Returned:(VMCB=%x)\n", info->vmm_data); 
-  //PrintDebug("RIP: %x\n", guest_state->rip);
+  if (info->enable_profiler) {
+    rdtscll(info->profiler.start_time);
+  }
 
   
   //PrintDebug("SVM Returned: Exit Code: %x\n",exit_code); 
   // END OF SWITCH (EXIT_CODE)
 
 
+  if (info->enable_profiler) {
+    rdtscll(info->profiler.end_time);
+    v3_profile_exit(info, exit_code);
+  }
+      
+
+
   // Update the low level state
 
   if (v3_intr_pending(info)) {
 
 #include <palacios/vmm_debug.h>
 #include <palacios/vmm_msr.h>
 #include <palacios/vmm_decoder.h>
+#include <palacios/vmm_profiler.h>
+#include <palacios/vmm_mem.h>
 
 #include <devices/serial.h>
 #include <devices/keyboard.h>
 #include <devices/bochs_debug.h>
 
 
+
 #include <palacios/vmm_host_events.h>
 
 #define USE_GENERIC 1
   setup_devices(info, config_ptr);
  
 
+
+  if (config_ptr->enable_profiling) {
+    info->enable_profiler = 1;
+    v3_init_profiler(info);
+  } else {
+    info->enable_profiler = 0;
+  }
+
   //v3_hook_io_port(info, 1234, &IO_Read, NULL, info);
 
   // Setup initial cpu register state
 
 
 
 
+int hashtable_inc(struct hashtable * htable, addr_t key, addr_t value) {
+    struct hash_entry * tmp_entry;
+    uint_t hash_value;
+    uint_t index;
+
+    hash_value = do_hash(htable, key);
+
+    index = indexFor(htable->table_length, hash_value);
+
+    tmp_entry = htable->table[index];
+
+    while (tmp_entry != NULL) {
+        /* Check hash value to short circuit heavier comparison */
+        if ((hash_value == tmp_entry->hash) && (htable->eq_fn(key, tmp_entry->key))) {
+
+         tmp_entry->value += value;
+         return -1;
+        }
+        tmp_entry = tmp_entry->next;
+    }
+    return 0;
+}
+
+
+int hashtable_dec(struct hashtable * htable, addr_t key, addr_t value) {
+    struct hash_entry * tmp_entry;
+    uint_t hash_value;
+    uint_t index;
+
+    hash_value = do_hash(htable, key);
+
+    index = indexFor(htable->table_length, hash_value);
+
+    tmp_entry = htable->table[index];
+
+    while (tmp_entry != NULL) {
+        /* Check hash value to short circuit heavier comparison */
+        if ((hash_value == tmp_entry->hash) && (htable->eq_fn(key, tmp_entry->key))) {
+
+         tmp_entry->value -= value;
+         return -1;
+        }
+        tmp_entry = tmp_entry->next;
+    }
+    return 0;
+}
+
+
+
 
 /*****************************************************************************/
 /* returns value associated with key */
 
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National 
+ * Science Foundation and the Department of Energy.  
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico.  You can find out more at 
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
 
 #ifdef USE_VMM_PAGING_DEBUG
 
 
--- /dev/null
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National 
+ * Science Foundation and the Department of Energy.  
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico.  You can find out more at 
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#include <palacios/vmm_types.h>
+#include <palacios/vmm_profiler.h>
+#include <palacios/svm_handler.h>
+#include <palacios/vmm_rbtree.h>
+
+
+struct exit_event {
+  uint_t exit_code;
+  uint_t exit_count;
+  uint_t handler_time;
+
+  struct rb_node tree_node;
+};
+
+
+void v3_init_profiler(struct guest_info * info) {
+  info->profiler.total_exits = 0;
+
+  info->profiler.start_time = 0;
+  info->profiler.end_time = 0;  
+
+  info->profiler.root.rb_node = NULL;
+}
+
+
+
+static inline struct exit_event * __insert_event(struct guest_info * info, 
+                                                struct exit_event * evt) {
+  struct rb_node ** p = &(info->profiler.root.rb_node);
+  struct rb_node * parent = NULL;
+  struct exit_event * tmp_evt = NULL;
+
+  while (*p) {
+    parent = *p;
+    tmp_evt = rb_entry(parent, struct exit_event, tree_node);
+
+    if (evt->exit_code < tmp_evt->exit_code) {
+      p = &(*p)->rb_left;
+    } else if (evt->exit_code > tmp_evt->exit_code) {
+      p = &(*p)->rb_right;
+    } else {
+      return tmp_evt;
+    }
+  }
+  rb_link_node(&(evt->tree_node), parent, p);
+
+  return NULL;
+}
+
+static inline struct exit_event * insert_event(struct guest_info * info, 
+                                              struct exit_event * evt) {
+  struct exit_event * ret;
+
+  if ((ret = __insert_event(info, evt))) {
+    return ret;
+  }
+
+  v3_rb_insert_color(&(evt->tree_node), &(info->profiler.root));
+
+  return NULL;
+}
+
+
+static struct exit_event * get_exit(struct guest_info * info, uint_t exit_code) {
+  struct rb_node * n = info->profiler.root.rb_node;
+  struct exit_event * evt = NULL;
+
+  while (n) {
+    evt = rb_entry(n, struct exit_event, tree_node);
+    
+    if (exit_code < evt->exit_code) {
+      n = n->rb_left;
+    } else if (exit_code > evt->exit_code) {
+      n = n->rb_right;
+    } else {
+      return evt;
+    }
+  }
+
+  return NULL;
+}
+
+
+static inline struct exit_event * create_exit(uint_t exit_code) {
+  struct exit_event * evt = V3_Malloc(sizeof(struct exit_event));
+
+  evt->exit_code = exit_code;
+  evt->exit_count = 0;
+  evt->handler_time = 0;
+
+  return evt;
+}
+
+void v3_profile_exit(struct guest_info * info, uint_t exit_code) {
+  uint_t time = (info->profiler.end_time - info->profiler.start_time);
+  struct exit_event * evt = get_exit(info, exit_code);
+
+  if (evt == NULL) {
+    evt = create_exit(exit_code);
+    insert_event(info, evt);
+  }
+
+  evt->handler_time += time;
+  evt->exit_count++;
+  
+  info->profiler.total_exits++;
+}
+
+
+void v3_print_profile(struct guest_info * info) {
+  struct exit_event * evt = NULL;
+  struct rb_node * node = v3_rb_first(&(info->profiler.root));
+  
+  do {
+    evt = rb_entry(node, struct exit_event, tree_node);
+
+    PrintDebug("%s: Cnt=%u, Time=%u\n", 
+              vmexit_code_to_str(evt->exit_code),
+              evt->exit_count,
+              evt->handler_time);
+              
+  } while ((node = v3_rb_next(node)));
+}
 
 
 
 
-DEFINE_HASHTABLE_INSERT(add_cr3_to_cache, addr_t, struct hashtable *);
-DEFINE_HASHTABLE_SEARCH(find_cr3_in_cache, addr_t, struct hashtable *);
-DEFINE_HASHTABLE_REMOVE(del_cr3_from_cache, addr_t, struct hashtable *, 0);
+//DEFINE_HASHTABLE_INSERT(add_cr3_to_cache, addr_t, struct hashtable *);
+//DEFINE_HASHTABLE_SEARCH(find_cr3_in_cache, addr_t, struct hashtable *);
+//DEFINE_HASHTABLE_REMOVE(del_cr3_from_cache, addr_t, struct hashtable *, 0);
 
 
 DEFINE_HASHTABLE_INSERT(add_pte_map, addr_t, addr_t);
 DEFINE_HASHTABLE_SEARCH(find_pte_map, addr_t, addr_t);
-DEFINE_HASHTABLE_REMOVE(del_pte_map, addr_t, addr_t, 0);
+//DEFINE_HASHTABLE_REMOVE(del_pte_map, addr_t, addr_t, 0);