]>
Commit | Line | Data |
---|---|---|
619c3a42 AZ |
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 | #ifndef __PERF_COUNTER_H | |
18 | #define __PERF_COUNTER_H 1 | |
19 | ||
20 | /* Motivation | |
21 | * ========== | |
22 | * | |
23 | * It is sometimes desirable to gain performance insights of a program | |
24 | * by using hardware counters. Recent Linux kernels started to support | |
25 | * a set of portable API for configuring and access those counter across | |
26 | * multiple platforms. | |
27 | * | |
28 | * APIs provided by perf-counter.h provides a set of APIs that are | |
29 | * semi-integrated into OVS user spaces. The infrastructure that initializes, | |
30 | * cleanup, display and clear them at run time is provided. However the | |
31 | * sample points are not. A programmer needs insert sample points when needed. | |
32 | * | |
33 | * Since there is no pre configured sample points, there is no run time | |
34 | * over head for the released product. | |
35 | * | |
36 | * Limitations | |
37 | * =========== | |
38 | * - Hard coded to sample CPU cycle count in user space only. | |
39 | * - Only one counter is sampled. | |
40 | * - Useful macros are only provided for function profiling. | |
41 | * - show and clear command applies to all counters, there is no way | |
42 | * to select a sub-set of counter. | |
43 | * | |
44 | * Those are not fundamental limits, but only limited by current | |
45 | * implementation. | |
46 | * | |
73ec82bf AZ |
47 | * Usage: |
48 | * ======= | |
619c3a42 | 49 | * |
73ec82bf AZ |
50 | * Adding performance counter is easy. Simply use the following macro to |
51 | * wrap around the expression you are interested in measuring. | |
619c3a42 | 52 | * |
73ec82bf | 53 | * PERF(name, expr). |
619c3a42 | 54 | * |
73ec82bf AZ |
55 | * The 'expr' is a set of C expressions you are interested in measuring. |
56 | * 'name' is the counter name. | |
619c3a42 | 57 | * |
73ec82bf | 58 | * For example, if we are interested in performance of perf_func(): |
619c3a42 | 59 | * |
73ec82bf AZ |
60 | * int perf_func() { |
61 | * <implemenation> | |
619c3a42 AZ |
62 | * } |
63 | * | |
73ec82bf AZ |
64 | * void func() { |
65 | * int rt; | |
619c3a42 | 66 | * |
73ec82bf AZ |
67 | * ... |
68 | * PERF("perf_func", rt = perf_func()); | |
619c3a42 | 69 | * |
73ec82bf AZ |
70 | * return rt; |
71 | * } | |
619c3a42 | 72 | * |
619c3a42 | 73 | * |
73ec82bf AZ |
74 | * This will maintain the number of times 'perf_func()' is called, total |
75 | * number of instructions '<implementation>' plus function call overhead | |
76 | * executed. | |
619c3a42 | 77 | * |
619c3a42 AZ |
78 | */ |
79 | ||
8790a8b4 | 80 | #if defined(__linux__) && defined(HAVE_LINUX_PERF_EVENT_H) |
619c3a42 AZ |
81 | struct perf_counter { |
82 | const char *name; | |
83 | bool once; | |
84 | uint64_t n_events; | |
85 | uint64_t total_count; | |
86 | }; | |
87 | ||
88 | #define PERF_COUNTER_ONCE_INITIALIZER(name) \ | |
89 | { \ | |
90 | name, \ | |
91 | false, \ | |
92 | 0, \ | |
93 | 0, \ | |
94 | } | |
95 | ||
96 | void perf_counters_init(void); | |
97 | void perf_counters_destroy(void); | |
98 | void perf_counters_clear(void); | |
99 | ||
100 | uint64_t perf_counter_read(uint64_t *counter); | |
101 | void perf_counter_accumulate(struct perf_counter *counter, | |
102 | uint64_t start_count); | |
103 | char *perf_counters_to_string(void); | |
104 | ||
105 | /* User access macros. */ | |
73ec82bf AZ |
106 | #define PERF(name, expr) \ |
107 | { \ | |
108 | static struct perf_counter c = PERF_COUNTER_ONCE_INITIALIZER(name);\ | |
109 | uint64_t start_count = perf_counter_read(&start_count); \ | |
110 | \ | |
111 | expr; \ | |
112 | \ | |
113 | perf_counter_accumulate(&c, start_count); \ | |
114 | } | |
619c3a42 | 115 | #else |
e8154139 | 116 | #define PERF(name, expr) { expr; } |
d663136e AZ |
117 | |
118 | static inline void perf_counters_init(void) {} | |
119 | static inline void perf_counters_destroy(void) {} | |
120 | static inline void perf_counters_clear(void) {} | |
121 | static inline char * | |
122 | perf_counters_to_string(void) | |
123 | { | |
9a6156bb | 124 | return xstrdup("Not Supported on this platform. Only available on Linux (version >= 2.6.32)"); |
d663136e AZ |
125 | } |
126 | ||
619c3a42 AZ |
127 | #endif |
128 | ||
129 | #endif |