1/** \file 2 * \brief Hello World application 3 */ 4 5/* 6 * Copyright (c) 2010, 2011, 2012, ETH Zurich. 7 * All rights reserved. 8 * 9 * This file is distributed under the terms in the attached LICENSE file. 10 * If you do not find this file, copies can be found by writing to: 11 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 12 */ 13 14#include <stdio.h> 15#include <stdlib.h> 16#include <string.h> 17#include <barrelfish/barrelfish.h> 18#include <arch/x86/barrelfish_kpi/perfmon.h> 19#include <barrelfish/lmp_endpoints.h> 20 21#define max(x,y) ((x) > (y) ? (x) : (y)) 22 23// Store result 24// current size: 8 bytes 25struct perfmon_data_buffer { 26 uint64_t ip; 27 char name[PERFMON_DISP_NAME_LEN]; 28}; 29#define PF_DATA_MAX 10000 30// Name of the domain to measure (cropped to length 8) 31#define PF_DOMAIN "monitor" 32static struct perfmon_data_buffer pf_data[PF_DATA_MAX]; 33static uint64_t pf_data_ptr = 0; 34 35// Endpoint for interrupt handlers 36static struct capref epcap; 37static struct lmp_endpoint *ep; 38 39static uint64_t overflow_ctr; 40static uint64_t max_outstanding; 41 42/* 43 * \brief Performance counter overflow handler 44 * 45 * Whenever the performance counter overflows the current instruction pointer 46 * along with the name of the running task is send as payload to this endpoint. 47 * The data is buffered. Therefore, this handler might be able to retrieve 48 * several messages from the buffer as soon as it is scheduled. 49 */ 50static void overflow_handler(void *args) 51{ 52 errval_t err; 53 uint64_t this_outstanding = 0; 54 55 // Retrieve the payload 56 do { 57 struct lmp_recv_msg msg = LMP_RECV_MSG_INIT; 58 err = lmp_endpoint_recv(ep, &msg.buf, NULL); 59 60 if (err_is_ok(err)) { 61 62 this_outstanding++; 63 64 struct perfmon_overflow_data data; 65 memcpy(&data, &msg.words, sizeof(data)); 66 67 char res[PERFMON_DISP_NAME_LEN+1]; 68 memset(res, '\0', PERFMON_DISP_NAME_LEN+1); 69 70 strncpy(res, data.name, PERFMON_DISP_NAME_LEN); 71 72 overflow_ctr++; 73 74 // Future work 75 // domain id from dispatcher 76 // spawnd to translate the id to name 77 // see: ps in shell 78 79 // Store if comming from sk_server task .. 80 if(pf_data_ptr<PF_DATA_MAX) { 81 82 pf_data[pf_data_ptr] = (struct perfmon_data_buffer) { .ip = data.ip }; 83 memcpy(pf_data[pf_data_ptr].name, res, PERFMON_DISP_NAME_LEN); 84 pf_data_ptr++; 85 86 if(pf_data_ptr==PF_DATA_MAX) { 87 88 // Stop performance monitoring 89 invoke_perfmon_deactivate(cap_perfmon); 90 91 // Print result .. 92 printf("Perfmon Overflow data START\n"); 93 for(uint64_t i=0; i<PF_DATA_MAX; i++) { 94 printf("PerfMon: %" PRIx64 " %.*s\n", 95 pf_data[i].ip, (int)PERFMON_DISP_NAME_LEN, pf_data[i].name); 96 } 97 // Don't change this line, as that will break 98 // the harness test "perfmontest" 99 printf("Perfmon Overflow data END\n"); 100 } 101 } 102 103 } else if (err_no(err) == LIB_ERR_NO_LMP_MSG) { 104 105 max_outstanding = max(max_outstanding, this_outstanding); 106 107 } else { 108 109 DEBUG_ERR(err, "Cannot read payload in performance counter " 110 "overflow \n"); 111 } 112 113 } while(err_is_ok(err)); 114 115 // Need to re-register .. 116 struct event_closure cl = { 117 .handler = overflow_handler 118 }; 119 err = lmp_endpoint_register(ep, get_default_waitset(), cl); 120 assert(err_is_ok(err)); 121 122} 123 124/* 125 * \brief Initialize endpoint for performance monitor overflow notifications. 126 */ 127static void interrupt_endpoint_init(void) 128{ 129 errval_t err; 130 131 /* Register notification endpoint with kernel */ 132 err = endpoint_create(250 * 12, &epcap, &ep); 133 if (err_is_fail(err)) { 134 USER_PANIC_ERR(err, "failed creating endpoint"); 135 } 136 137 // Register endpoint. This should set up the endpoint. 138 struct event_closure cl = { 139 .handler = overflow_handler 140 }; 141 err = lmp_endpoint_register(ep, get_default_waitset(), cl); 142 assert(err_is_ok(err)); 143} 144 145int main(int argc, char *argv[]) 146{ 147 errval_t err; 148 overflow_ctr = 0; 149 max_outstanding = 0; 150 151 // Setup the endpoint for performance counter overflows 152 interrupt_endpoint_init(); 153 154 // Starting performance monitoring. 155 // Assuming, that the capability has been given to us by init>monitor>spawn 156 err = invoke_perfmon_activate(cap_perfmon, 157 0x76, // Event to monitor 158 ~0x0, // UMASK 159 false, // Kernel 160 0, // Counter ID 161 250000, // number of events to cause overflow 162 get_cap_addr(epcap)); 163 // SAMPLE events to monitor for recent AMD machines. 164 // 0x7e L2 cache misses 165 // 0x76 CPU clocks not halt 166 // SAMPLE events to monitor for Intel machines. 167 // 0x3C Unhalted core cycles (umask = 0) 168 169 assert(err_is_ok(err)); 170 if(err_is_fail(err)) { 171 USER_PANIC_ERR(err, "invoke_perfmon_activate"); 172 } 173 174 // Wait for overflows 175 struct waitset *ws = get_default_waitset(); 176 while (1) { 177 err = event_dispatch(ws); 178 if (err_is_fail(err)) { 179 USER_PANIC_ERR(err, "Performance counter overflow handler died"); 180 break; 181 } 182 } 183 184 // do never terminate 185 assert(false); 186} 187 188