~ubuntu-branches/ubuntu/wily/openvswitch/wily

« back to all changes in this revision

Viewing changes to lib/perf-counter.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2015-08-10 11:35:15 UTC
  • mfrom: (1.1.30)
  • Revision ID: package-import@ubuntu.com-20150810113515-575vj06oq29emxsn
Tags: 2.4.0~git20150810.97bab95-0ubuntu1
* New upstream snapshot from 2.4 branch:
  - d/*: Align any relevant packaging changes with upstream.
* d/*: wrap-and-sort.
* d/openvswitch-{common,vswitch}.install: Correct install location for
  bash completion files.
* d/tests/openflow.py: Explicitly use ovs-testcontroller as provided
  by 2.4.0 release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2015 Nicira, Inc.
 
3
 *
 
4
 * Licensed under the Apache License, Version 2.0 (the "License");
 
5
 * you may not use this file except in compliance with the License.
 
6
 * You may obtain a copy of the License at:
 
7
 *
 
8
 *     http://www.apache.org/licenses/LICENSE-2.0
 
9
 *
 
10
 * Unless required by applicable law or agreed to in writing, software
 
11
 * distributed under the License is distributed on an "AS IS" BASIS,
 
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
13
 * See the License for the specific language governing permissions and
 
14
 * limitations under the License.
 
15
 */
 
16
 
 
17
/* This implementation only applies to the Linux platform.  */
 
18
 
 
19
#include <config.h>
 
20
#if defined(__linux__) && defined(HAVE_LINUX_PERF_EVENT_H)
 
21
 
 
22
#include <stddef.h>
 
23
#include <sys/types.h>
 
24
#include <stdlib.h>
 
25
#include <unistd.h>
 
26
#include <sys/ioctl.h>
 
27
#include <linux/perf_event.h>
 
28
#include <asm/unistd.h>
 
29
#include "dynamic-string.h"
 
30
#include "perf-counter.h"
 
31
#include "shash.h"
 
32
#include "util.h"
 
33
 
 
34
static struct shash perf_counters;
 
35
static int fd__ = 0;
 
36
 
 
37
uint64_t
 
38
perf_counter_read(uint64_t *counter)
 
39
{
 
40
    int size = sizeof *counter;
 
41
 
 
42
    if (fd__ <= 0 || read(fd__, counter, size) < size) {
 
43
        *counter = 0;
 
44
    }
 
45
 
 
46
    return *counter;
 
47
}
 
48
 
 
49
static long
 
50
perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
 
51
                int cpu, int group_fd, unsigned long flags)
 
52
{
 
53
    int ret;
 
54
 
 
55
    ret = syscall(__NR_perf_event_open, hw_event, pid, cpu,
 
56
                  group_fd, flags);
 
57
    return ret;
 
58
}
 
59
 
 
60
/* Set up perf event counters to read user space instruction counters
 
61
 * only for this process, on all cpus.   */
 
62
static void
 
63
perf_event_setup(void)
 
64
{
 
65
    struct perf_event_attr pe;
 
66
 
 
67
    memset(&pe, 0, sizeof(struct perf_event_attr));
 
68
    pe.type = PERF_TYPE_HARDWARE;
 
69
    pe.size = sizeof(struct perf_event_attr);
 
70
    pe.config = PERF_COUNT_HW_INSTRUCTIONS;
 
71
    pe.disabled = 1;
 
72
    pe.exclude_kernel = 1;
 
73
    pe.exclude_hv = 1;
 
74
 
 
75
    fd__ = perf_event_open(&pe, 0, -1, -1, 0);
 
76
    if (fd__ > 0) {
 
77
        ioctl(fd__, PERF_EVENT_IOC_RESET, 0);
 
78
        ioctl(fd__, PERF_EVENT_IOC_ENABLE, 0);
 
79
    }
 
80
}
 
81
 
 
82
static void
 
83
perf_counter_init(struct perf_counter *counter)
 
84
{
 
85
    counter->once = true;
 
86
    shash_add_assert(&perf_counters, counter->name, counter);
 
87
}
 
88
 
 
89
void
 
90
perf_counter_accumulate(struct perf_counter *counter, uint64_t start_count)
 
91
{
 
92
    uint64_t end_count;
 
93
 
 
94
    if (!counter->once) {
 
95
        perf_counter_init(counter);
 
96
    }
 
97
 
 
98
    counter->n_events++;
 
99
    perf_counter_read(&end_count);
 
100
    counter->total_count += end_count - start_count;
 
101
}
 
102
 
 
103
static void
 
104
perf_counter_to_ds(struct ds *ds, struct perf_counter *pfc)
 
105
{
 
106
    double ratio;
 
107
 
 
108
    if (pfc->n_events) {
 
109
        ratio = (double)pfc->total_count / (double)pfc->n_events;
 
110
    } else {
 
111
        ratio = 0.0;
 
112
    }
 
113
 
 
114
    ds_put_format(ds, "%-40s%12"PRIu64"%12"PRIu64"%12.1f\n",
 
115
                  pfc->name, pfc->n_events, pfc->total_count, ratio);
 
116
}
 
117
 
 
118
static void
 
119
perf_counters_to_ds(struct ds *ds)
 
120
{
 
121
    const char *err_str;
 
122
    const struct shash_node **sorted;
 
123
    int i;
 
124
 
 
125
    err_str = NULL;
 
126
    if (fd__ == -1) {
 
127
        err_str = "performance counter is not supported on this platfrom";
 
128
    } else if (!shash_count(&perf_counters)) {
 
129
        err_str = "performance counter has never been hit";
 
130
    }
 
131
 
 
132
    if (err_str) {
 
133
        ds_put_format(ds, "%s\n", err_str);
 
134
        return;
 
135
    }
 
136
 
 
137
    /* Display counters in alphabetical order.  */
 
138
    sorted = shash_sort(&perf_counters);
 
139
    for (i = 0; i < shash_count(&perf_counters); i++) {
 
140
        perf_counter_to_ds(ds, sorted[i]->data);
 
141
    }
 
142
    free(sorted);
 
143
}
 
144
 
 
145
/*
 
146
 * Caller is responsible for free memory.
 
147
 */
 
148
char *
 
149
perf_counters_to_string()
 
150
{
 
151
    struct ds ds;
 
152
 
 
153
    ds_init(&ds);
 
154
    perf_counters_to_ds(&ds);
 
155
    return ds_steal_cstr(&ds);
 
156
}
 
157
 
 
158
void
 
159
perf_counters_init(void)
 
160
{
 
161
    shash_init(&perf_counters);
 
162
    perf_event_setup();
 
163
}
 
164
 
 
165
void
 
166
perf_counters_clear(void)
 
167
{
 
168
    struct shash_node *node;
 
169
 
 
170
    SHASH_FOR_EACH (node, &perf_counters) {
 
171
        struct perf_counter *perf = node->data;
 
172
 
 
173
        perf->n_events = 0;
 
174
        perf->total_count = 0;
 
175
    }
 
176
}
 
177
 
 
178
void
 
179
perf_counters_destroy()
 
180
{
 
181
    struct shash_node *node, *next;
 
182
 
 
183
    if (fd__ != -1) {
 
184
        ioctl(fd__, PERF_EVENT_IOC_DISABLE, 0);
 
185
        close(fd__);
 
186
    }
 
187
 
 
188
    SHASH_FOR_EACH_SAFE (node, next, &perf_counters) {
 
189
        shash_delete(&perf_counters, node);
 
190
    }
 
191
 
 
192
    shash_destroy(&perf_counters);
 
193
}
 
194
#endif