Processor Counter Monitor
lspci.h
1 #ifndef CPUCounters_LSPCI_H
2 #define CPUCounters_LSPCI_H
3 
4 #include <vector>
5 #include <fstream>
6 #include <memory>
7 #include "cpucounters.h"
8 
9 #if defined(_MSC_VER)
10 #define PCI_IDS_PATH "pci.ids"
11 #define PCI_IDS_NOT_FOUND "pci.ids file is not available. Download it from" \
12  " https://raw.githubusercontent.com/pciutils/pciids/master/pci.ids."
13 #elif defined (__FreeBSD__) || defined(__DragonFly__)
14 #define PCI_IDS_PATH "/usr/local/share/pciids/pci.ids"
15 #define PCI_IDS_NOT_FOUND "/usr/local/share/pciids/pci.ids file is not available." \
16  " Ensure that the \"pciids\" package is properly installed or download" \
17  " https://raw.githubusercontent.com/pciutils/pciids/master/pci.ids and" \
18  " copy it to the current directory."
19 #else
20 #define PCI_IDS_PATH "/usr/share/hwdata/pci.ids"
21 #define PCI_IDS_NOT_FOUND "/usr/share/hwdata/pci.ids file is not available." \
22  " Ensure that the \"hwdata\" package is properly installed or download" \
23  " https://raw.githubusercontent.com/pciutils/pciids/master/pci.ids and" \
24  " copy it to the current directory."
25 #endif
26 
27 namespace pcm {
28 
29 typedef uint32_t h_id;
30 typedef uint32_t v_id;
31 typedef std::map<std::pair<h_id,v_id>,uint64_t> ctr_data;
32 typedef std::vector<ctr_data> stack_content;
33 typedef std::vector<stack_content> result_content;
34 
35 class ccr {
36  public:
37  virtual uint64_t get_event_select() const = 0;
38  virtual void set_event_select(uint64_t value) = 0;
39  virtual uint64_t get_umask() const = 0;
40  virtual void set_umask(uint64_t value) = 0;
41  virtual uint64_t get_reset() const = 0;
42  virtual void set_reset(uint64_t value) = 0;
43  virtual uint64_t get_edge() const = 0;
44  virtual void set_edge(uint64_t value) = 0;
45  virtual uint64_t get_ov_en() const = 0;
46  virtual void set_ov_en(uint64_t value) = 0;
47  virtual uint64_t get_enable() const = 0;
48  virtual void set_enable(uint64_t value) = 0;
49  virtual uint64_t get_invert() const = 0;
50  virtual void set_invert(uint64_t value) = 0;
51  virtual uint64_t get_thresh() const = 0;
52  virtual void set_thresh(uint64_t value) = 0;
53  virtual uint64_t get_ch_mask() const = 0;
54  virtual void set_ch_mask(uint64_t value) = 0;
55  virtual uint64_t get_fc_mask() const = 0;
56  virtual void set_fc_mask(uint64_t value) = 0;
57  virtual uint64_t get_ccr_value() const = 0;
58  virtual void set_ccr_value(uint64_t value) = 0;
59  virtual ~ccr() {};
60 };
61 
62 class skx_ccr: public ccr {
63  public:
64  skx_ccr(uint64_t &v){
65  ccr_value = &v;
66  }
67  virtual uint64_t get_event_select() const {
68  return (*ccr_value & 0xFF);
69  }
70  virtual void set_event_select(uint64_t value) {
71  *ccr_value |= value;
72  }
73  virtual uint64_t get_umask() const {
74  return ((*ccr_value >> 8) & 0xFF);
75  }
76  virtual void set_umask(uint64_t value) {
77  *ccr_value |= (value << 8);
78  }
79  virtual uint64_t get_reset() const {
80  return ((*ccr_value >> 17) & 0x01);
81  }
82  virtual void set_reset(uint64_t value) {
83  *ccr_value |= (value << 17);
84  }
85  virtual uint64_t get_edge() const {
86  return ((*ccr_value >> 18) & 0x01);
87  }
88  virtual void set_edge(uint64_t value) {
89  *ccr_value |= (value << 18);
90  }
91  virtual uint64_t get_ov_en() const {
92  return ((*ccr_value >> 20) & 0x01);
93  }
94  virtual void set_ov_en(uint64_t value) {
95  *ccr_value |= (value << 20);
96  }
97  virtual uint64_t get_enable() const {
98  return ((*ccr_value >> 22) & 0x01);
99  }
100  virtual void set_enable(uint64_t value) {
101  *ccr_value |= (value << 22);
102  }
103  virtual uint64_t get_invert() const {
104  return ((*ccr_value >> 23) & 0x01);
105  }
106  virtual void set_invert(uint64_t value) {
107  *ccr_value |= (value << 23);
108  }
109  virtual uint64_t get_thresh() const {
110  return ((*ccr_value >> 24) & 0xFFF);
111  }
112  virtual void set_thresh(uint64_t value) {
113  *ccr_value |= (value << 24);
114  }
115  virtual uint64_t get_ch_mask() const {
116  return ((*ccr_value >> 36) & 0xFF);
117  }
118  virtual void set_ch_mask(uint64_t value) {
119  *ccr_value |= (value << 36);
120  }
121  virtual uint64_t get_fc_mask() const {
122  return ((*ccr_value >> 44) & 0x07);
123  }
124  virtual void set_fc_mask(uint64_t value) {
125  *ccr_value |= (value << 44);
126  }
127  virtual uint64_t get_ccr_value() const {
128  return *ccr_value;
129  }
130  virtual void set_ccr_value(uint64_t value) {
131  *ccr_value = value;
132  }
133 
134  private:
135  uint64_t* ccr_value = NULL;
136 };
137 
138 class icx_ccr: public ccr {
139  public:
140  icx_ccr(uint64_t &v){
141  ccr_value = &v;
142  }
143  virtual uint64_t get_event_select() const {
144  return (*ccr_value & 0xFF);
145  }
146  virtual void set_event_select(uint64_t value) {
147  *ccr_value |= value;
148  }
149  virtual uint64_t get_umask() const {
150  return ((*ccr_value >> 8) & 0xFF);
151  }
152  virtual void set_umask(uint64_t value) {
153  *ccr_value |= (value << 8);
154  }
155  virtual uint64_t get_reset() const {
156  return ((*ccr_value >> 17) & 0x01);
157  }
158  virtual void set_reset(uint64_t value) {
159  *ccr_value |= (value << 17);
160  }
161  virtual uint64_t get_edge() const {
162  return ((*ccr_value >> 18) & 0x01);
163  }
164  virtual void set_edge(uint64_t value) {
165  *ccr_value |= (value << 18);
166  }
167  virtual uint64_t get_ov_en() const {
168  return ((*ccr_value >> 20) & 0x01);
169  }
170  virtual void set_ov_en(uint64_t value) {
171  *ccr_value |= (value << 20);
172  }
173  virtual uint64_t get_enable() const {
174  return ((*ccr_value >> 22) & 0x01);
175  }
176  virtual void set_enable(uint64_t value) {
177  *ccr_value |= (value << 22);
178  }
179  virtual uint64_t get_invert() const {
180  return ((*ccr_value >> 23) & 0x01);
181  }
182  virtual void set_invert(uint64_t value) {
183  *ccr_value |= (value << 23);
184  }
185  virtual uint64_t get_thresh() const {
186  return ((*ccr_value >> 24) & 0xFFF);
187  }
188  virtual void set_thresh(uint64_t value) {
189  *ccr_value |= (value << 24);
190  }
191  virtual uint64_t get_ch_mask() const {
192  return ((*ccr_value >> 36) & 0xFFF);
193  }
194  virtual void set_ch_mask(uint64_t value) {
195  *ccr_value |= (value << 36);
196  }
197  virtual uint64_t get_fc_mask() const {
198  return ((*ccr_value >> 48) & 0x07);
199  }
200  virtual void set_fc_mask(uint64_t value) {
201  *ccr_value |= (value << 48);
202  }
203  virtual uint64_t get_ccr_value() const {
204  return *ccr_value;
205  }
206  virtual void set_ccr_value(uint64_t value) {
207  *ccr_value = value;
208  }
209 
210  private:
211  uint64_t* ccr_value = NULL;
212  };
213 struct bdf {
214  uint8_t busno;
215  uint8_t devno;
216  uint8_t funcno;
217  bdf () : busno(0), devno(0), funcno(0) {}
218 };
219 
220 struct pci {
221  bool exist = false;
222  struct bdf bdf;
223  union {
224  struct {
225  uint16_t vendor_id;
226  uint16_t device_id;
227  };
228  uint32_t offset_0;
229  };
230  int8_t header_type;
231  union {
232  struct {
233  uint8_t primary_bus_number;
234  uint8_t secondary_bus_number;
235  uint8_t subordinate_bus_number;
236  uint8_t junk;
237  };
238  uint32_t offset_18;
239  };
240  union {
241  struct {
242  uint16_t link_ctrl;
243  union {
244  struct {
245  uint16_t link_speed : 4;
246  uint16_t link_width : 6;
247  uint16_t undefined : 1;
248  uint16_t link_trained : 1;
249  };
250  uint16_t link_sta;
251  };
252  };
253  uint32_t link_info;
254  };
255  pci () : exist(false), offset_0(0), header_type(0), offset_18(0), link_info(0) {}
256 };
257 
258 struct counter {
259  std::string h_event_name;
260  std::string v_event_name;
261  uint64_t ccr;
262  int idx; /* Some counters need to be placed in specific index */
263  int multiplier;
264  int divider;
265  uint32_t h_id;
266  uint32_t v_id;
267  std::vector<result_content> data;
268 };
269 
270 struct iio_skx {
271  struct {
272  struct {
273  struct pci root_pci_dev; /* single device represent root port */
274  std::vector<struct pci> child_pci_devs; /* Contain child switch and end-point devices */
275  } parts[4]{}; /* part 0, 1, 2, 3 */
276  uint8_t busno{}; /* holding busno for each IIO stack */
277  std::string stack_name{};
278  std::vector<uint64_t> values{};
279  bool flipped = false;
280  } stacks[6]; /* iio stack 0, 1, 2, 3, 4, 5 */
281  uint32_t socket_id{};
282 };
283 
285  int part_id;
286  /* single device represent root port */
287  struct pci root_pci_dev;
288  /* Contain child switch and end-point devices */
289  std::vector<struct pci> child_pci_devs;
290 };
291 
292 struct iio_stack {
293  std::vector<struct iio_bifurcated_part> parts{};
294  uint32_t iio_unit_id{};
295  std::string stack_name{};
296  std::vector<uint64_t> values{};
297  bool flipped = false;
298  /* holding busno for each IIO stack */
299  uint8_t busno{};
300 };
301 
302 bool operator<(const iio_stack& lh, const iio_stack& rh)
303 {
304  return lh.iio_unit_id < rh.iio_unit_id;
305 }
306 
308  std::vector<struct iio_stack> stacks{};
309  uint32_t socket_id{};
310 };
311 
312 bool operator < (const bdf &l, const bdf &r) {
313  if (l.busno < r.busno)
314  return true;
315  if (l.busno > r.busno)
316  return false;
317  if (l.devno < r.devno)
318  return true;
319  if (l.devno > r.devno)
320  return false;
321  if (l.funcno < r.funcno)
322  return true;
323  if (l.funcno > r.funcno)
324  return false;
325 
326  return false; // bdf == bdf
327 };
328 
329 void probe_capability_pci_express(struct pci *p, uint32_t cap_ptr)
330 {
331  struct cap {
332  union {
333  struct {
334  uint8_t id;
335  union {
336  uint8_t next;
337  uint8_t cap_ptr;
338  };
339  uint16_t junk;
340  };
341  uint32 dw0;
342  };
343  } cap;
344  uint32 value;
345  PciHandleType h(0, p->bdf.busno, p->bdf.devno, p->bdf.funcno);
346  h.read32(cap_ptr, &value); //Capability pointer
347  cap.dw0 = value;
348  if (cap.id != 0x10 && cap.next != 0x00) {
349  probe_capability_pci_express(p, cap.cap_ptr);
350  } else {
351  if (cap.id == 0x10) { // We're in PCI express capability structure
352  h.read32(cap_ptr+0x10, &value);
353  p->link_info = value;
354  } else { /*Finish recursive searching but cannot find PCI express capability structure*/ }
355  }
356 }
357 
358 bool probe_pci(struct pci *p)
359 {
360  uint32 value;
361  p->exist = false;
362  struct bdf *bdf = &p->bdf;
363  if (PciHandleType::exists(0, bdf->busno, bdf->devno, bdf->funcno)) {
364  PciHandleType h(0, bdf->busno, bdf->devno, bdf->funcno);
365  // VID:DID
366  h.read32(0x0, &value);
367  // Invalid VID::DID
368  if (value != (std::numeric_limits<unsigned int>::max)()) {
369  p->offset_0 = value;
370  h.read32(0xc, &value);
371  p->header_type = (value >> 16) & 0x7f;
372  if (p->header_type == 0) {
373  // Status register
374  h.read32(0x4, &value);
375  // Capability list == true
376  if (value & 0x100000) {
377  // Capability pointer
378  h.read32(0x34, &value);
379  probe_capability_pci_express(p, value);
380  }
381  } else if (p->header_type == 1) {
382  h.read32(0x18, &value);
383  p->offset_18 = value;
384  }
385  p->exist = true;
386  }
387  }
388 
389  return p->exist;
390 }
391 
392 /*
393  first : [vendorID] -> vencor name
394  second : [vendorID][deviceID] -> device name
395  */
396 typedef std::pair< std::map<int, std::string> ,std::map< int, std::map<int, std::string> > > PCIDB;
397 
398 void print_pci(struct pci p, const PCIDB & pciDB)
399 {
400  printf("Parent bridge info:");
401  printf("%x:%x.%d [%04x:%04x] %s %s %d P:%x S:%x S:%x ",
402  p.bdf.busno, p.bdf.devno, p.bdf.funcno,
403  p.vendor_id, p.device_id,
404  (pciDB.first.count(p.vendor_id) > 0)?pciDB.first.at(p.vendor_id).c_str():"unknown vendor",
405  (pciDB.second.count(p.vendor_id) > 0 && pciDB.second.at(p.vendor_id).count(p.device_id) > 0)?pciDB.second.at(p.vendor_id).at(p.device_id).c_str():"unknown device",
406  p.header_type,
407  p.primary_bus_number, p.secondary_bus_number, p.subordinate_bus_number);
408  printf("Device info:");
409  printf("%x:%x.%d [%04x:%04x] %s %s %d Gen%d x%d\n",
410  p.bdf.busno, p.bdf.devno, p.bdf.funcno,
411  p.vendor_id, p.device_id,
412  (pciDB.first.count(p.vendor_id) > 0)?pciDB.first.at(p.vendor_id).c_str():"unknown vendor",
413  (pciDB.second.count(p.vendor_id) > 0 && pciDB.second.at(p.vendor_id).count(p.device_id) > 0)?pciDB.second.at(p.vendor_id).at(p.device_id).c_str():"unknown device",
414  p.header_type,
415  p.link_speed, p.link_width);
416 }
417 
418 void load_PCIDB(PCIDB & pciDB)
419 {
420  std::ifstream in(PCI_IDS_PATH);
421  std::string line, item;
422 
423  if (!in.is_open())
424  {
425 #ifndef _MSC_VER
426  // On Unix, try the current directory if the default path failed
427  in.open("pci.ids");
428  }
429 
430  if (!in.is_open())
431  {
432 #endif
433  std::cerr << PCI_IDS_NOT_FOUND << "\n";
434  return;
435  }
436 
437  int vendorID = -1;
438 
439  while (std::getline(in, line)) {
440  // Ignore any line starting with #
441  if (line.size() == 0 || line[0] == '#')
442  continue;
443 
444  if (line[0] == '\t' && line[1] == '\t')
445  {
446  // subvendor subdevice subsystem_name
447  continue;
448  }
449  if (line[0] == '\t')
450  {
451  int deviceID = stoi(line.substr(1,4),0,16);
452  //std::cout << vendorID << ";" << vendorName << ";" << deviceID << ";" << line.substr(7) << "\n";
453  pciDB.second[vendorID][deviceID] = line.substr(7);
454  continue;
455  }
456  // vendor
457  vendorID = stoi(line.substr(0,4),0,16);
458  pciDB.first[vendorID] = line.substr(6);
459  }
460 }
461 
462 } // namespace pcm
463 
464 #endif
Definition: lspci.h:138
Definition: lspci.h:220
Definition: lspci.h:292
Definition: lspci.h:258
Definition: lspci.h:62
Definition: lspci.h:213
Main CPU counters header.
Definition: bw.cpp:12
Definition: lspci.h:284
Definition: lspci.h:35
Definition: lspci.h:270
Definition: lspci.h:307
Definition: pcm-iio.cpp:146