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