Skip to content

Commit 982fb7a

Browse files
committed
implement pcm-tpmi utility
Change-Id: Ic853168b08d31e84e46cd229d2ede788ef9e3c19
1 parent 0bf18dd commit 982fb7a

File tree

2 files changed

+209
-1
lines changed

2 files changed

+209
-1
lines changed

‎src/CMakeLists.txt‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44

55
# All pcm-* executables
6-
set(PROJECT_NAMES pcm pcm-numa pcm-latency pcm-power pcm-msr pcm-memory pcm-tsx pcm-pcie pcm-core pcm-iio pcm-lspci pcm-pcicfg pcm-mmio pcm-raw pcm-accel)
6+
set(PROJECT_NAMES pcm pcm-numa pcm-latency pcm-power pcm-msr pcm-memory pcm-tsx pcm-pcie pcm-core pcm-iio pcm-lspci pcm-pcicfg pcm-mmio pcm-tpmi pcm-raw pcm-accel)
77

88
file(GLOB COMMON_SOURCES msr.cpp cpucounters.cpp pci.cpp mmio.cpp bw.cpp utils.cpp topology.cpp debug.cpp threadpool.cpp uncore_pmu_discovery.cpp)
99

‎src/pcm-tpmi.cpp‎

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
// SPDX-License-Identifier: BSD-3-Clause
2+
// Copyright (c) 2023 Intel Corporation
3+
4+
// written by Roman Dementiev
5+
#include "cpucounters.h"
6+
#ifdef _MSC_VER
7+
#include <windows.h>
8+
#include "windows/windriver.h"
9+
#else
10+
#include <unistd.h>
11+
#endif
12+
#include <iostream>
13+
#include <stdlib.h>
14+
#include <iomanip>
15+
#include <string.h>
16+
#ifdef _MSC_VER
17+
#include "freegetopt/getopt.h"
18+
#endif
19+
20+
using namespace pcm;
21+
22+
void print_usage(const char * progname)
23+
{
24+
std::cout << "Usage " << progname << " [-w value] [-d] [-b low:high] ID offset\n\n";
25+
std::cout << " Reads/writes TPMI (Topology Aware Register and PM Capsule Interface) register \n";
26+
std::cout << " ID : TPMI ID\n";
27+
std::cout << " offset : register offset\n";
28+
std::cout << " -w value : write the value before reading \n";
29+
std::cout << " -b low:high : read or write only low..high bits of the register\n";
30+
std::cout << " -d : output all numbers in dec (default is hex)\n";
31+
std::cout << " -v : verbose ouput\n";
32+
std::cout << " --version : print application version\n";
33+
std::cout << "\n";
34+
}
35+
36+
PCM_MAIN_NOTHROW;
37+
38+
int mainThrows(int argc, char * argv[])
39+
{
40+
if(print_version(argc, argv))
41+
return 0;
42+
43+
std::cout << "\n Intel(r) Performance Counter Monitor " << PCM_VERSION << "\n";
44+
45+
std::cout << "\n TPMI (Topology Aware Register and PM Capsule Interface) read/write utility\n\n";
46+
47+
uint64 value = 0;
48+
bool write = false;
49+
bool dec = false;
50+
bool verbose = false;
51+
std::pair<int64,int64> bits{-1, -1};
52+
53+
int my_opt = -1;
54+
while ((my_opt = getopt(argc, argv, "w:dvb:")) != -1)
55+
{
56+
switch (my_opt)
57+
{
58+
case 'w':
59+
write = true;
60+
value = (pcm::uint32)read_number(optarg);
61+
break;
62+
case 'd':
63+
dec = true;
64+
break;
65+
case 'v':
66+
verbose = true;
67+
break;
68+
case 'b':
69+
{
70+
const auto bitsArray = pcm::split(std::string(optarg),':');
71+
assert(bitsArray.size() == 2);
72+
bits.first = (int64)read_number(bitsArray[0].c_str());
73+
bits.second = (int64)read_number(bitsArray[1].c_str());
74+
assert(bits.first >= 0);
75+
assert(bits.second >= 0);
76+
assert(bits.first < 64);
77+
assert(bits.second < 64);
78+
if (bits.first > bits.second)
79+
{
80+
std::swap(bits.first, bits.second);
81+
}
82+
}
83+
break;
84+
default:
85+
print_usage(argv[0]);
86+
return -1;
87+
}
88+
}
89+
90+
if (optind + 1 >= argc)
91+
{
92+
print_usage(argv[0]);
93+
return -1;
94+
}
95+
96+
uint64 requestedID = (uint64)read_number(argv[optind]);
97+
uint64 requestedRelativeOffset = (uint64)read_number(argv[optind + 1]);
98+
99+
#ifdef _MSC_VER
100+
// Increase the priority a bit to improve context switching delays on Windows
101+
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
102+
103+
// WARNING: This driver code (msr.sys) is only for testing purposes, not for production use
104+
Driver drv = Driver(Driver::msrLocalPath());
105+
// drv.stop(); // restart driver (usually not needed)
106+
if (!drv.start())
107+
{
108+
tcerr << "Can not load MSR driver.\n";
109+
tcerr << "You must have a signed driver at " << drv.driverPath() << " and have administrator rights to run this program\n";
110+
return -1;
111+
}
112+
#endif
113+
114+
processDVSEC([](const VSEC & vsec)
115+
{
116+
return vsec.fields.cap_id == 0xb // Vendor Specific DVSEC
117+
&& vsec.fields.vsec_id == 0x42; // TPMI PM_Features
118+
}, [&](const uint64 bar, const VSEC & vsec)
119+
{
120+
struct PFS
121+
{
122+
uint64 TPMI_ID:8;
123+
uint64 NumEntries:8;
124+
uint64 EntrySize:16;
125+
uint64 CapOffset:16;
126+
uint64 Attribute:2;
127+
uint64 Reserved:14;
128+
};
129+
static_assert(sizeof(PFS) == sizeof(uint64), "sizeof(PFS) != sizeof(uint64)");
130+
assert(vsec.fields.EntrySize == 2);
131+
std::vector<PFS> pfsArray(vsec.fields.NumEntries);
132+
pcm::mmio_memcpy(&(pfsArray[0]), bar + vsec.fields.Address, vsec.fields.NumEntries * sizeof(PFS), true);
133+
for (const auto & pfs : pfsArray)
134+
{
135+
if (verbose)
136+
{
137+
std::cout << "PFS" <<
138+
"\t TPMI_ID: " << pfs.TPMI_ID <<
139+
"\t NumEntries: " << pfs.NumEntries <<
140+
"\t EntrySize: " << pfs.EntrySize <<
141+
"\t CapOffset: " << pfs.CapOffset <<
142+
"\t Attribute: " << pfs.Attribute <<
143+
"\n";
144+
}
145+
for (uint64 p = 0; p < pfs.NumEntries; ++p)
146+
{
147+
uint32 reg0 = 0;
148+
const auto addr = bar + vsec.fields.Address + pfs.CapOffset * 1024ULL + p * pfs.EntrySize * sizeof(uint32);
149+
mmio_memcpy(&reg0, addr, sizeof(uint32), false);
150+
if (reg0 == ~0U)
151+
{
152+
if (verbose)
153+
{
154+
std::cout << "invalid entry " << p << "\n";
155+
}
156+
}
157+
else if (pfs.TPMI_ID == requestedID)
158+
{
159+
if (verbose)
160+
{
161+
std::cout << "Entry "<< p << std::hex;
162+
for (uint64 i_offset = 0; i_offset < pfs.EntrySize * sizeof(uint32); i_offset += sizeof(uint64))
163+
{
164+
uint64 reg = 0;
165+
mmio_memcpy(&reg, addr + i_offset, sizeof(uint64), false);
166+
std::cout << " register "<< i_offset << " = " << reg;
167+
}
168+
std::cout << std::dec << "\n";
169+
}
170+
try {
171+
const auto requestedAddr = addr + requestedRelativeOffset;
172+
const auto baseAddr = roundDownTo4K(requestedAddr);
173+
const auto baseOffset = requestedAddr - baseAddr;
174+
MMIORange range(baseAddr, 4096ULL, !write);
175+
if (!dec) std::cout << std::hex << std::showbase;
176+
if (bits.first >= 0 && write)
177+
{
178+
// to write bits need to read the old value first
179+
uint64 old_value = range.read64(baseOffset);
180+
value = insertBits(old_value, value, bits.first, bits.second - bits.first + 1);
181+
}
182+
if (write)
183+
{
184+
std::cout << " Writing " << value << " to TPMI ID " << requestedID << "@" << requestedRelativeOffset << " for entry " << p << "\n";
185+
range.write64(baseOffset, value);
186+
}
187+
value = range.read64(baseOffset);
188+
std::cout << " Read ";
189+
if (bits.first >= 0)
190+
{
191+
std::cout << "bits "<< std::dec << bits.first << ":" << bits.second << " ";
192+
if (!dec) std::cout << std::hex << std::showbase;
193+
value = extract_bits(value, bits.first, bits.second);
194+
}
195+
std::cout << "value " << value << " from TPMI ID " << requestedID << "@" << requestedRelativeOffset << " for entry " << p << "\n\n";
196+
}
197+
catch (std::exception& e)
198+
{
199+
std::cerr << "Error accessing registers: " << e.what() << "\n";
200+
std::cerr << "Please check if the program can access MSR/PCICFG drivers.\n";
201+
}
202+
}
203+
}
204+
}
205+
});
206+
207+
return 0;
208+
}

0 commit comments

Comments
 (0)