Impala
Impalaistheopensource,nativeanalyticdatabaseforApacheHadoop.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
perf-counters.cc
Go to the documentation of this file.
1 // Copyright 2012 Cloudera Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 // TODO: "Performance Counters for Linux" is not supported in Linux < 2.6.31.
16 // This file will not compile under RHEL 5 or any of it's derivitives.
17 
18 #include "util/perf-counters.h"
19 #include "util/debug-util.h"
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include <fstream>
26 #include <iomanip>
27 #include <iostream>
28 #include <sstream>
29 
30 #include <sys/syscall.h>
31 #include <linux/perf_event.h>
32 
33 #define COUNTER_SIZE (sizeof(void*))
34 #define BUFFER_SIZE 256
35 #define PRETTY_PRINT_WIDTH 13
36 
37 #include "common/names.h"
38 
39 namespace impala {
40 
41 // This is the order of the counters in /proc/self/io
51 };
52 
53 // Wrapper around sys call. This syscall is hard to use and this is how it is recommended
54 // to be used.
55 static inline int sys_perf_event_open(
56  struct perf_event_attr* attr,
57  pid_t pid, int cpu, int group_fd,
58  unsigned long flags) {
59  attr->size = sizeof(*attr);
60  return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
61 }
62 
63 // Remap PerfCounters::Counter to Linux kernel enums
64 static bool InitEventAttr(perf_event_attr* attr, PerfCounters::Counter counter) {
65  memset(attr, 0, sizeof(perf_event_attr));
66 
67  switch (counter) {
69  attr->type = PERF_TYPE_SOFTWARE;
70  attr->config = PERF_COUNT_SW_CPU_CLOCK;
71  break;
73  attr->type = PERF_TYPE_SOFTWARE;
74  attr->config = PERF_COUNT_SW_PAGE_FAULTS;
75  break;
77  attr->type = PERF_TYPE_SOFTWARE;
78  attr->config = PERF_COUNT_SW_PAGE_FAULTS;
79  break;
81  attr->type = PERF_TYPE_SOFTWARE;
82  attr->config = PERF_COUNT_SW_CPU_MIGRATIONS;
83  break;
85  attr->type = PERF_TYPE_HARDWARE;
86  attr->config = PERF_COUNT_HW_CPU_CYCLES;
87  break;
89  attr->type = PERF_TYPE_HARDWARE;
90  attr->config = PERF_COUNT_HW_INSTRUCTIONS;
91  break;
93  attr->type = PERF_TYPE_HARDWARE;
94  attr->config = PERF_COUNT_HW_CACHE_REFERENCES;
95  break;
97  attr->type = PERF_TYPE_HARDWARE;
98  attr->config = PERF_COUNT_HW_CACHE_MISSES;
99  break;
101  attr->type = PERF_TYPE_HARDWARE;
102  attr->config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS;
103  break;
105  attr->type = PERF_TYPE_HARDWARE;
106  attr->config = PERF_COUNT_HW_BRANCH_MISSES;
107  break;
109  attr->type = PERF_TYPE_HARDWARE;
110  attr->config = PERF_COUNT_HW_BUS_CYCLES;
111  break;
112  default:
113  return false;
114  }
115 
116  return true;
117 }
118 
119 static string GetCounterName(PerfCounters::Counter counter) {
120  switch (counter) {
122  return "CPUTime";
124  return "PageFaults";
126  return "ContextSwitches";
128  return "CPUMigrations";
130  return "HWCycles";
132  return "Instructions";
134  return "CacheHit";
136  return "CacheMiss";
138  return "Branches";
140  return "BranchMiss";
142  return "BusCycles";
144  return "VmUsage";
146  return "PeakVmUsage";
148  return "WorkingSet";
150  return "BytesRead";
152  return "BytesWritten";
154  return "DiskRead";
156  return "DiskWrite";
157  default:
158  return "";
159  }
160 }
161 
163  CounterData data;
164  data.counter = counter;
166  data.fd = -1;
167  perf_event_attr attr;
168  if (!InitEventAttr(&attr, counter)) {
169  return false;
170  }
171  int fd = sys_perf_event_open(&attr, getpid(), -1, group_fd_, 0);
172  if (fd < 0) {
173  return false;
174  }
175  if (group_fd_ == -1) {
176  group_fd_ = fd;
177  }
178  data.fd = fd;
179 
180  if (counter == PERF_COUNTER_SW_CPU_CLOCK) {
181  data.type = TUnit::TIME_NS;
182  } else {
183  data.type = TUnit::UNIT;
184  }
185  counters_.push_back(data);
186  return true;
187 }
188 
190  CounterData data;
191  data.counter = counter;
193  data.type = TUnit::BYTES;
194 
195  switch (counter) {
198  break;
201  break;
204  break;
207  break;
208  default:
209  return false;
210  }
211  counters_.push_back(data);
212  return true;
213 }
214 
216  CounterData data;
217  data.counter = counter;
219  data.type = TUnit::BYTES;
220 
221  switch (counter) {
223  data.proc_status_field = "VmSize";
224  break;
226  data.proc_status_field = "VmPeak";
227  break;
229  data.proc_status_field = "VmRS";
230  break;
231  default:
232  return false;
233  }
234  counters_.push_back(data);
235  return true;
236 }
237 
238 bool PerfCounters::GetSysCounters(vector<int64_t>& buffer) {
239  for (int i = 0; i < counters_.size(); i++) {
240  if (counters_[i].source == SYS_PERF_COUNTER) {
241  int num_bytes = read(counters_[i].fd, &buffer[i], COUNTER_SIZE);
242  if (num_bytes != COUNTER_SIZE) return false;
243  if (counters_[i].type == TUnit::TIME_NS) {
244  buffer[i] /= 1000000;
245  }
246  }
247  }
248  return true;
249 }
250 
251 // Parse out IO counters from /proc/self/io. The file contains a list of
252 // (name,byte) pairs.
253 // For example:
254 // rchar: 210212
255 // wchar: 94
256 // syscr: 118
257 // syscw: 3
258 // read_bytes: 0
259 // write_bytes: 0
260 // cancelled_write_bytes: 0
261 bool PerfCounters::GetProcSelfIOCounters(vector<int64_t>& buffer) {
262  ifstream file("/proc/self/io", ios::in);
263  string buf;
264  int64_t values[PROC_IO_LAST_COUNTER];
265 
266  for (int i = 0; i < PROC_IO_LAST_COUNTER; ++i) {
267  if (!file) goto end;
268  getline(file, buf);
269  size_t colon = buf.find(':');
270  if (colon == string::npos) goto end;
271  buf = buf.substr(colon + 1);
272  istringstream stream(buf);
273  stream >> values[i];
274  }
275 
276  for (int i = 0; i < counters_.size(); ++i) {
277  if (counters_[i].source == PROC_SELF_IO) {
278  buffer[i] = values[counters_[i].proc_io_line_number];
279  }
280  }
281 end:
282  if (file.is_open()) file.close();
283  return true;
284 }
285 
286 bool PerfCounters::GetProcSelfStatusCounters(vector<int64_t>& buffer) {
287  ifstream file("/proc/self/status", ios::in);
288  string buf;
289 
290  while (file) {
291  getline(file, buf);
292  for (int i = 0; i < counters_.size(); ++i) {
293  if (counters_[i].source == PROC_SELF_STATUS) {
294  size_t field = buf.find(counters_[i].proc_status_field);
295  if (field == string::npos) continue;
296  size_t colon = field + counters_[i].proc_status_field.size() + 1;
297  buf = buf.substr(colon + 1);
298  istringstream stream(buf);
299  int64_t value;
300  stream >> value;
301  buffer[i] = value * 1024; // values in file are in kb
302  }
303  }
304  }
305  if (file.is_open()) file.close();
306  return true;
307 }
308 
309 PerfCounters::PerfCounters() : group_fd_(-1) {
310 }
311 
312 // Close all fds for the counters
314  for (int i = 0; i < counters_.size(); ++i) {
315  if (counters_[i].source == SYS_PERF_COUNTER) {
316  close(counters_[i].fd);
317  }
318  }
319 }
320 
321 // Add here the default ones that are most useful
323  bool result = true;
325  // These hardware ones don't work on a vm, just ignore if they fail
326  // TODO: these don't work reliably and aren't that useful. Turn them off.
327  //AddCounter(PERF_COUNTER_HW_INSTRUCTIONS);
328  //AddCounter(PERF_COUNTER_HW_CPU_CYCLES);
329  //AddCounter(PERF_COUNTER_HW_BRANCHES);
330  //AddCounter(PERF_COUNTER_HW_BRANCH_MISSES);
331  //AddCounter(PERF_COUNTER_HW_CACHE_MISSES);
336  return result;
337 }
338 
339 // Add a specific counter
341  // Ignore if it's already added.
342  for (int i = 0; i < counters_.size(); ++i) {
343  if (counters_[i].counter == counter) {
344  return true;
345  }
346  }
347  bool result = false;
348  switch (counter) {
360  result = InitSysCounter(counter);
361  break;
366  result = InitProcSelfIOCounter(counter);
367  break;
371  result = InitProcSelfStatusCounter(counter);
372  break;
373  default:
374  return false;
375  }
376  if (result) counter_names_.push_back(GetCounterName(counter));
377  return result;
378 }
379 
380 // Query all the counters right now and store the values in results
381 void PerfCounters::Snapshot(const string& name) {
382  if (counters_.size() == 0) {
383  return;
384  }
385 
386  string fixed_name = name;
387  if (fixed_name.size() == 0) {
388  stringstream ss;
389  ss << snapshots_.size() + 1;
390  fixed_name = ss.str();
391  }
392 
393  vector<int64_t> buffer(counters_.size());
394 
395  GetSysCounters(buffer);
396  GetProcSelfIOCounters(buffer);
398 
399  snapshots_.push_back(buffer);
400  snapshot_names_.push_back(fixed_name);
401 }
402 
403 const vector<int64_t>* PerfCounters::counters(int snapshot) const {
404  if (snapshot < 0 || snapshot >= snapshots_.size()) return NULL;
405  return &snapshots_[snapshot];
406 }
407 
408 void PerfCounters::PrettyPrint(ostream* s) const {
409  ostream& stream = *s;
410  stream << setw(8) << "Snapshot";
411  for (int i = 0; i < counter_names_.size(); ++i) {
412  stream << setw(PRETTY_PRINT_WIDTH) << counter_names_[i];
413  }
414  stream << endl;
415 
416  for (int s = 0; s < snapshots_.size(); s++) {
417  stream << setw(8) << snapshot_names_[s];
418  const vector<int64_t>& snapshot = snapshots_[s];
419  for (int i = 0; i < snapshot.size(); ++i) {
420  stream << setw(PRETTY_PRINT_WIDTH) << PrettyPrinter::Print(snapshot[i], counters_[i].type);
421  }
422  stream << endl;
423  }
424  stream << endl;
425 }
426 
427 }
428 
const StringSearch UrlParser::colon_search & colon
Definition: url-parser.cc:39
bool InitSysCounter(Counter counter)
std::string proc_status_field
For PROC_SELF_STATUS. Field name for counter.
bool InitProcSelfIOCounter(Counter counter)
bool GetProcSelfIOCounters(std::vector< int64_t > &snapshot)
std::vector< std::vector< int64_t > > snapshots_
void PrettyPrint(std::ostream *out) const
Prints out the names and results for all snapshots to 'out'.
bool InitProcSelfStatusCounter(Counter counter)
static std::string Print(bool value, TUnit::type ignored, bool verbose=false)
bool GetProcSelfStatusCounters(std::vector< int64_t > &snapshot)
int fd
For SYS_PERF_COUNTER. File descriptor where the counter value is stored.
std::vector< std::string > counter_names_
static string GetCounterName(PerfCounters::Counter counter)
bool GetSysCounters(std::vector< int64_t > &snapshot)
std::vector< std::string > snapshot_names_
int proc_io_line_number
For PROC_SELF_IO. Line number from /proc/self/io file with this counter's value.
void Snapshot(const std::string &name="")
static bool InitEventAttr(perf_event_attr *attr, PerfCounters::Counter counter)
bool AddCounter(Counter)
std::vector< CounterData > counters_
static int sys_perf_event_open(struct perf_event_attr *attr, pid_t pid, int cpu, int group_fd, unsigned long flags)
string name
Definition: cpu-info.cc:50
#define PRETTY_PRINT_WIDTH
const std::vector< int64_t > * counters(int snapshot) const
Returns the results of that snapshot.
#define COUNTER_SIZE