Initial commit
This commit is contained in:
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "third_party/farmhash"]
|
||||
path = third_party/farmhash
|
||||
url = https://github.com/google/farmhash
|
155
CMakeLists.txt
Normal file
155
CMakeLists.txt
Normal file
@@ -0,0 +1,155 @@
|
||||
# Copyright 2020 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
cmake_minimum_required (VERSION 3.2)
|
||||
project (cpu_check VERSION 20181130 LANGUAGES C CXX)
|
||||
|
||||
# Options
|
||||
# Use clang/llvm by default.
|
||||
option(USE_CLANG "build with clang" ON)
|
||||
# Build semi-statically by default.
|
||||
option(BUILD_STATIC "build targets semi-statically linked" ON)
|
||||
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Release)
|
||||
endif(NOT CMAKE_BUILD_TYPE)
|
||||
|
||||
|
||||
# Begin Google local change
|
||||
|
||||
# We use an in tree copy of boringSSL by default.
|
||||
option(USE_BORINGSSL "build with boringSSL" OFF)
|
||||
|
||||
option(IN_GOOGLE3 "building in google3" OFF)
|
||||
|
||||
# The vendors subdirectories may not be present.
|
||||
find_path(
|
||||
VENDORS_AMD_PATH
|
||||
NAMES amd.cc
|
||||
PATHS ${CMAKE_CURRENT_SOURCE_DIR}/vendors/amd
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
|
||||
find_path(
|
||||
VENDORS_INTEL_PATH
|
||||
NAMES intel.cc
|
||||
PATHS ${CMAKE_CURRENT_SOURCE_DIR}/vendors/intel
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
# End Google local change
|
||||
|
||||
# Config header
|
||||
configure_file (
|
||||
"${PROJECT_SOURCE_DIR}/config.h.in"
|
||||
"${PROJECT_BINARY_DIR}/config.h"
|
||||
)
|
||||
include_directories("${PROJECT_BINARY_DIR}")
|
||||
|
||||
if (USE_CLANG)
|
||||
set(CMAKE_C_COMPILER clang)
|
||||
set(CMAKE_CXX_COMPILER clang++)
|
||||
set(CC clang)
|
||||
set(CXX clang++)
|
||||
endif(USE_CLANG)
|
||||
|
||||
set(CMAKE_C_FLAGS_DEBUG "-g -Wall -O0")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-g -Wall -O0")
|
||||
set(CMAKE_C_FLAGS_RELEASE "-Wall -O2")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-Wall -O2")
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_C_EXTENSIONS OFF) # we want c11 not gnu11
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF) # we want c++17 not gnu++17
|
||||
|
||||
add_executable(cpu_check cpu_check.cc)
|
||||
add_executable(crc32c_test crc32c_test.cc)
|
||||
|
||||
add_library(farmhash third_party/farmhash/src/farmhash.cc)
|
||||
add_library(crc32c crc32c.c)
|
||||
add_library(fvt_controller fvt_controller.cc)
|
||||
add_library(utils utils.cc)
|
||||
|
||||
# Begin Google local change
|
||||
if (VENDORS_AMD_PATH)
|
||||
add_library(amd ${VENDORS_AMD_PATH}/amd.cc)
|
||||
add_library(hsmp ${VENDORS_AMD_PATH}/hsmp.cc)
|
||||
target_link_libraries(amd hsmp pci)
|
||||
set(VENDORS_LIBS ${VENDORS_LIBS} amd)
|
||||
endif(VENDORS_AMD_PATH)
|
||||
|
||||
if (VENDORS_INTEL_PATH)
|
||||
add_library(intel ${VENDORS_INTEL_PATH}/intel.cc)
|
||||
set(VENDORS_LIBS ${VENDORS_LIBS} intel)
|
||||
endif(VENDORS_INTEL_PATH)
|
||||
# End Google local change
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
check_cxx_compiler_flag("-march=sandybridge" ARCH_SANDYBRIDGE)
|
||||
if(ARCH_SANDYBRIDGE)
|
||||
target_compile_options(farmhash PUBLIC -march=sandybridge)
|
||||
target_compile_options(crc32c PUBLIC -march=sandybridge)
|
||||
endif(ARCH_SANDYBRIDGE)
|
||||
|
||||
target_link_libraries(cpu_check crc32c farmhash)
|
||||
# Begin Google local change
|
||||
target_link_libraries(cpu_check fvt_controller ${VENDORS_LIBS} utils)
|
||||
# End Google local change
|
||||
target_link_libraries(crc32c_test crc32c)
|
||||
|
||||
if (BUILD_STATIC)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
|
||||
endif(BUILD_STATIC)
|
||||
|
||||
# Needs pthreads
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(cpu_check Threads::Threads)
|
||||
|
||||
# Needs zlib
|
||||
find_package (ZLIB REQUIRED)
|
||||
if(ZLIB_INCLUDE_DIRS)
|
||||
include_directories(${ZLIB_INCLUDE_DIRS})
|
||||
endif(ZLIB_INCLUDE_DIRS)
|
||||
if(ZLIB_LIBRARIES)
|
||||
target_link_libraries(cpu_check ${ZLIB_LIBRARIES})
|
||||
endif(ZLIB_LIBRARIES)
|
||||
|
||||
# Begin Google local change
|
||||
if(USE_BORINGSSL)
|
||||
set(BORINGSSL_PATH ${CMAKE_CURRENT_SOURCE_DIR}/boringssl)
|
||||
add_subdirectory(${BORINGSSL_PATH})
|
||||
set(BORINGSSL_INCLUDE_DIRS ${BORINGSSL_PATH}/include)
|
||||
include_directories("${BORINGSSL_PATH}/include")
|
||||
target_link_libraries(cpu_check ssl crypto)
|
||||
else(USE_BORINGSSL)
|
||||
# End Google local change
|
||||
|
||||
# Needs OpenSSL
|
||||
find_package (OpenSSL REQUIRED)
|
||||
include_directories(${OPENSSL_INCLUDE_DIRS})
|
||||
target_link_libraries(cpu_check ${OPENSSL_LIBRARIES})
|
||||
|
||||
# Static linking of OpenSSL may require -ldl, link it if found.
|
||||
find_library (dl dl)
|
||||
if(dl)
|
||||
target_link_libraries(cpu_check dl)
|
||||
endif(dl)
|
||||
|
||||
# Begin Google local change
|
||||
endif(USE_BORINGSSL)
|
||||
# End Google local change
|
||||
|
||||
install (TARGETS cpu_check DESTINATION bin)
|
22
CONTRIBUTING
Normal file
22
CONTRIBUTING
Normal file
@@ -0,0 +1,22 @@
|
||||
How to Contribute
|
||||
|
||||
Contributions are encouraged! Please read below for requirements.
|
||||
|
||||
## Contributor License Agreement
|
||||
|
||||
Contributions to this project must be accompanied by a Contributor License
|
||||
Agreement. You (or your employer) retain the copyright to your contribution;
|
||||
this simply gives us permission to use and redistribute your contributions as
|
||||
part of the project. Head over to <https://cla.developers.google.com/> to see
|
||||
your current agreements on file or to sign a new one.
|
||||
|
||||
You generally only need to submit a CLA once, so if you've already submitted one
|
||||
(even if it was for a different project), you probably don't need to do it
|
||||
again.
|
||||
|
||||
## Code reviews
|
||||
|
||||
All submissions, including submissions by project members, require review. We
|
||||
use GitHub pull requests for this purpose. Consult
|
||||
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
|
||||
information on using pull requests.
|
217
LICENSE
Normal file
217
LICENSE
Normal file
@@ -0,0 +1,217 @@
|
||||
Copyright 2018 Paul Ripke <stixpjr@gmail.com>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
71
README.md
Normal file
71
README.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# cpu_check
|
||||
|
||||
`NOTE:` BETA code, work-in-progress.
|
||||
|
||||
CPU torture test designed for SMP systems, attempting to find CPU hardware faults, focusing primarily on the x86_64 architecture.
|
||||
|
||||
The basic operation is to:
|
||||
* Run threads with affinity fixed to each logical CPU.
|
||||
* Generate a chunk of random data, either dictionary based text, or random binary data.
|
||||
* Run a number of checksum/hash algorithms over the data, store their results.
|
||||
* Compress the data via one of (zlib, ...).
|
||||
* Encrypt the data via AES-256-GCM.
|
||||
* Copy the data ('rep movsb' on x86, else memcpy).
|
||||
* Switch affinity to an alternate logical CPU.
|
||||
* Decrypt.
|
||||
* Decompress.
|
||||
* Run checksum/hash algorithms and compare with stored results.
|
||||
|
||||
Algorithms are chosen to exercise various hardware extensions. Eg. on x86_64, SSE4.2, AVX, etc.
|
||||
|
||||
## Prerequisites:
|
||||
|
||||
Designed to run under Unix/Linux OS.
|
||||
|
||||
* cmake: https://cmake.org/
|
||||
* zlib
|
||||
* OpenSSL/BoringSSL
|
||||
|
||||
## Building
|
||||
|
||||
```
|
||||
sh$ git clone git@github.com:stixpjr/cpu_check.git
|
||||
sh$ cd cpu_check
|
||||
sh$ mkdir build
|
||||
sh$ cd build
|
||||
sh$ cmake ..
|
||||
sh$ make
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
Some options have been implememented that affect the build, which may be passed
|
||||
to cmake via, eg:
|
||||
|
||||
```cmake -DCMAKE_BUILD_TYPE=(Debug|Release)```
|
||||
|
||||
* CMAKE_BUILD_TYPE=(Release|Debug)
|
||||
* USE_CLANG=(ON|OFF)
|
||||
* BUILD_STATIC=(ON|OFF)
|
||||
|
||||
## TODO:
|
||||
|
||||
* Use git submodules for:
|
||||
* farmhash: https://github.com/google/farmhash
|
||||
* highwayhash: https://github.com/google/highwayhash
|
||||
* crc32c: https://github.com/google/crc32c
|
||||
* cityhash: https://github.com/google/cityhash
|
||||
* brotli: https://github.com/google/brotli
|
||||
* gipfeli: https://github.com/google/gipfeli
|
||||
* Expand encryption coverage - find those algorithms that stress the HW.
|
||||
* Flags to enable/disable steps, eg. encryption.
|
||||
* Flags controlling min/max buffer size.
|
||||
* Use cpuid to dynamically select appropriate instruction set extensions.
|
||||
* Query ACPI/cpuid for more meaningful CPU identification.
|
||||
* Extra x86_64 instruction coverage:
|
||||
* movnti (SSE2 mov doubleword with non-temporal hint)
|
||||
* prefetch*
|
||||
* movbe (mov with byte swap)
|
||||
* Consider floating point tests?
|
||||
* Keep stats on corruptions (eg. buffer lengths/alignments, detection means (crc32), etc).
|
||||
* Try to narrow down corruptions automatically.
|
8
config.h.in
Normal file
8
config.h.in
Normal file
@@ -0,0 +1,8 @@
|
||||
#define cpu_check_VERSION "@cpu_check_VERSION@"
|
||||
|
||||
// Begin Google local change
|
||||
#cmakedefine IN_GOOGLE3
|
||||
#cmakedefine USE_BORINGSSL
|
||||
#cmakedefine VENDORS_AMD_PATH
|
||||
#cmakedefine VENDORS_INTEL_PATH
|
||||
// End Google local change
|
200
corrupt_cores.cc
Normal file
200
corrupt_cores.cc
Normal file
@@ -0,0 +1,200 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Analyzes cpu_check failure tids to produce list of condemned
|
||||
// cores. Usually there's just one defective core.
|
||||
//
|
||||
// One way to extract tids from logs is extract_tids.sh.
|
||||
// Pipe its output to this program.
|
||||
//
|
||||
// By default, this code assumes 28 core dual socket machines.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
class BadCore {
|
||||
public:
|
||||
BadCore(int sockets, int cores_per_socket)
|
||||
: sockets_(sockets), cores_per_socket_(cores_per_socket) {}
|
||||
|
||||
// Condemns thread 'tid'.
|
||||
void Condemn(int tid) {
|
||||
std::vector<int> c({TidToCanonicalCore(tid)});
|
||||
accused_.push_back(c);
|
||||
}
|
||||
|
||||
// Condemns one of 'tid_1' and 'tid_2'.
|
||||
void Accuse(int tid_1, int tid_2) {
|
||||
std::vector<int> c({TidToCanonicalCore(tid_1), TidToCanonicalCore(tid_2)});
|
||||
accused_.push_back(c);
|
||||
}
|
||||
|
||||
// Greedy condemnation.
|
||||
void Condemn() {
|
||||
while (!accused_.empty()) {
|
||||
CondemnWorst();
|
||||
}
|
||||
}
|
||||
|
||||
// Returns string naming the condemned cores.
|
||||
std::string Condemnations() const {
|
||||
if (condemned_.empty()) {
|
||||
return "None";
|
||||
}
|
||||
std::stringstream s;
|
||||
if (ambiguous_) {
|
||||
s << "AMBIGUOUS ";
|
||||
}
|
||||
for (auto &c : condemned_) {
|
||||
s << CanonicalCoreToString(c.first) << " (" << c.second << ") ";
|
||||
}
|
||||
return s.str();
|
||||
}
|
||||
|
||||
// Returns true if tid within legitimate range.
|
||||
bool Plausible(int tid) const {
|
||||
return (tid >= 0) && (tid < (2 * sockets_ * cores_per_socket_));
|
||||
}
|
||||
|
||||
private:
|
||||
// Condemns worst offender.
|
||||
void CondemnWorst() {
|
||||
int worst = -1;
|
||||
int worst_k = -1;
|
||||
bool ambiguous = false;
|
||||
for (int c = 0; c < sockets_ * cores_per_socket_; c++) {
|
||||
const int k = AccusationCount(c);
|
||||
if (k == 0) continue;
|
||||
if (k > worst_k) {
|
||||
worst = c;
|
||||
worst_k = k;
|
||||
ambiguous = false;
|
||||
} else {
|
||||
if (k == worst_k) {
|
||||
ambiguous = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
ambiguous_ |= ambiguous;
|
||||
condemned_.push_back({worst, worst_k});
|
||||
Dispose(worst);
|
||||
}
|
||||
|
||||
// Returns number of accusations against 'canonical_core'.
|
||||
int AccusationCount(int canonical_core) const {
|
||||
int k = 0;
|
||||
for (auto &v : accused_) {
|
||||
if (std::find(v.begin(), v.end(), canonical_core) != v.end()) {
|
||||
k++;
|
||||
}
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
// Delete accusations that include 'canonical_core'.
|
||||
void Dispose(int canonical_core) {
|
||||
std::vector<std::vector<int>> temp;
|
||||
for (auto &v : accused_) {
|
||||
if (std::find(v.begin(), v.end(), canonical_core) == v.end()) {
|
||||
temp.push_back(v);
|
||||
}
|
||||
}
|
||||
accused_ = temp;
|
||||
}
|
||||
|
||||
int TidToCanonicalCore(int tid) const {
|
||||
return tid % (sockets_ * cores_per_socket_);
|
||||
}
|
||||
|
||||
std::string CanonicalCoreToString(int canonical_core) const {
|
||||
const int socket = canonical_core / cores_per_socket_;
|
||||
const int a = canonical_core;
|
||||
const int b = canonical_core + sockets_ * cores_per_socket_;
|
||||
std::stringstream s;
|
||||
s << "CPU" << socket << " HT" << a << "-" << b;
|
||||
return s.str();
|
||||
}
|
||||
|
||||
const int sockets_;
|
||||
const int cores_per_socket_;
|
||||
std::vector<std::vector<int>> accused_;
|
||||
std::vector<std::pair<int, int>> condemned_;
|
||||
bool ambiguous_ = false;
|
||||
};
|
||||
|
||||
static void UsageIf(bool v) {
|
||||
if (!v) return;
|
||||
LOG(ERROR) << "Usage corrupt_cores [-c cores_per_socket] [-s sockets]";
|
||||
exit(2);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int sockets = 2; // Default: dual socket
|
||||
int cores_per_socket = 28; // Default: C28
|
||||
for (int i = 1; i < argc; i++) {
|
||||
const char *flag = argv[i];
|
||||
UsageIf(flag[0] != '-');
|
||||
for (flag++; *flag != 0; flag++) {
|
||||
switch (*flag) {
|
||||
case 'c': {
|
||||
std::string c(++flag);
|
||||
flag += c.length();
|
||||
std::stringstream s(c);
|
||||
UsageIf((s >> cores_per_socket).fail());
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
std::string c(++flag);
|
||||
flag += c.length();
|
||||
std::stringstream s(c);
|
||||
UsageIf((s >> sockets).fail());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UsageIf(true);
|
||||
}
|
||||
if (*flag == 0) break;
|
||||
}
|
||||
}
|
||||
|
||||
std::string line;
|
||||
BadCore bad(sockets, cores_per_socket);
|
||||
|
||||
while (std::getline(std::cin, line)) {
|
||||
std::istringstream ss(line);
|
||||
int a = 9999;
|
||||
if ((ss >> a).fail() || !bad.Plausible(a)) {
|
||||
LOG(ERROR) << "Bad input: '" << line << "'";
|
||||
continue;
|
||||
}
|
||||
while (ss.peek() == ' ') ss.ignore();
|
||||
if (ss.eof()) {
|
||||
bad.Condemn(a);
|
||||
} else {
|
||||
int b = 9999;
|
||||
if ((ss >> b).fail() || !bad.Plausible(b)) {
|
||||
LOG(ERROR) << "Bad input: '" << line << "'";
|
||||
continue;
|
||||
}
|
||||
bad.Accuse(a, b);
|
||||
}
|
||||
}
|
||||
bad.Condemn();
|
||||
printf("Condemned %s\n", bad.Condemnations().c_str());
|
||||
}
|
2075
cpu_check.cc
Normal file
2075
cpu_check.cc
Normal file
File diff suppressed because it is too large
Load Diff
75
crc32c.c
Normal file
75
crc32c.c
Normal file
@@ -0,0 +1,75 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "crc32c.h"
|
||||
|
||||
#ifdef __SSE4_2__
|
||||
#include <x86intrin.h>
|
||||
|
||||
/* x86 version based using instrinsics */
|
||||
|
||||
uint32_t crc32c_hw(const char *src, size_t len) {
|
||||
const unsigned char *s = (unsigned char *)src;
|
||||
uint64_t hh = ~0;
|
||||
#ifdef __x86_64__
|
||||
while (len > 7) {
|
||||
uint64_t v = *(uint64_t *)s;
|
||||
hh = _mm_crc32_u64(hh, v);
|
||||
s += 8;
|
||||
len -= 8;
|
||||
}
|
||||
#endif /* __x86_64__ */
|
||||
uint32_t h = (uint32_t)hh;
|
||||
if (len > 3) {
|
||||
uint32_t v = *(uint32_t *)s;
|
||||
h = _mm_crc32_u32(h, v);
|
||||
s += 4;
|
||||
len -= 4;
|
||||
}
|
||||
if (len > 1) {
|
||||
uint16_t v = *(uint16_t *)s;
|
||||
h = _mm_crc32_u16(h, v);
|
||||
s += 2;
|
||||
len -= 2;
|
||||
}
|
||||
if (len > 0) {
|
||||
uint8_t v = *(uint8_t *)s;
|
||||
h = _mm_crc32_u8(h, v);
|
||||
s += 1;
|
||||
len -= 1;
|
||||
}
|
||||
return ~h;
|
||||
}
|
||||
#endif /* __SSE4_2__ */
|
||||
|
||||
/* CRC-32C (iSCSI) polynomial in reversed bit order. */
|
||||
#define POLY 0x82f63b78
|
||||
|
||||
uint32_t crc32c_sw(const char *src, size_t len) {
|
||||
const unsigned char *s = (unsigned char *)src;
|
||||
uint32_t h = ~0;
|
||||
while (len--) {
|
||||
h ^= *s++;
|
||||
for (int k = 0; k < 8; k++) h = h & 1 ? (h >> 1) ^ POLY : h >> 1;
|
||||
}
|
||||
return ~h;
|
||||
}
|
||||
|
||||
uint32_t crc32c(const char *src, size_t len) {
|
||||
#ifdef __SSE4_2__
|
||||
return crc32c_hw(src, len);
|
||||
#else
|
||||
return crc32c_sw(src, len);
|
||||
#endif
|
||||
}
|
27
crc32c.h
Normal file
27
crc32c.h
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
uint32_t crc32c(const char *s, size_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
52
crc32c_test.cc
Normal file
52
crc32c_test.cc
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
|
||||
#include "crc32c.h"
|
||||
|
||||
extern "C" {
|
||||
uint32_t crc32c_hw(const char *, size_t);
|
||||
uint32_t crc32c_sw(const char *, size_t);
|
||||
}
|
||||
|
||||
const int MINSIZE = 1;
|
||||
const int MAXSIZE = 1048576;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
std::knuth_b rndeng((std::random_device()()));
|
||||
std::uniform_int_distribution<int> size_dist(MINSIZE, MAXSIZE);
|
||||
std::uniform_int_distribution<int> d_dist(0, 255);
|
||||
std::string buf;
|
||||
for (int i = 0; i < 100; i++) {
|
||||
size_t len = size_dist(rndeng);
|
||||
buf.resize(len);
|
||||
for (size_t j = 0; j < len; j++) {
|
||||
buf[j] = d_dist(rndeng);
|
||||
}
|
||||
uint32_t crc_hw = crc32c_hw(buf.data(), len);
|
||||
uint32_t crc_sw = crc32c_sw(buf.data(), len);
|
||||
if (crc_hw != crc_sw) {
|
||||
fprintf(stderr, "crc mismatch: hw 0x%08x vs sw 0x%08x buffer len %ld\n",
|
||||
crc_hw, crc_sw, len);
|
||||
}
|
||||
buf.clear();
|
||||
}
|
||||
#endif // defined(__x86_64__) || defined(__i386__)
|
||||
return 0;
|
||||
}
|
127
fvt_controller.cc
Normal file
127
fvt_controller.cc
Normal file
@@ -0,0 +1,127 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "config.h"
|
||||
#include "fvt_controller.h"
|
||||
|
||||
#include <error.h>
|
||||
#include <fcntl.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <atomic>
|
||||
#undef NDEBUG
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include "fvt_controller.h"
|
||||
#include "log.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class NonX86FVTController : public FVTController {
|
||||
public:
|
||||
explicit NonX86FVTController(int cpu) : FVTController(cpu) {}
|
||||
~NonX86FVTController() override {}
|
||||
void SetCurrentFreqLimitMhz(int mhz) override {
|
||||
LOG(FATAL) << "Unsupported platform";
|
||||
}
|
||||
// Returns the maximum supported CPU frequency.
|
||||
int GetAbsoluteFreqLimitMhz() override {
|
||||
LOG(FATAL) << "Unsupported platform";
|
||||
return 0;
|
||||
}
|
||||
// Returns true if automatic Power Management enabled.
|
||||
bool PowerManaged() const override {
|
||||
LOG(FATAL) << "Unsupported platform";
|
||||
return false;
|
||||
}
|
||||
std::string FVT() override {
|
||||
LOG(FATAL) << "Unsupported platform";
|
||||
return "";
|
||||
}
|
||||
std::string InterestingEnables() const override {
|
||||
LOG(FATAL) << "Unsupported platform";
|
||||
return "";
|
||||
}
|
||||
void ControlFastStringOps(bool enable) override {
|
||||
LOG(FATAL) << "Unsupported platform";
|
||||
}
|
||||
|
||||
protected:
|
||||
int GetCurrentFreqLimitMhz() override {
|
||||
LOG(FATAL) << "Unsupported platform";
|
||||
return 0;
|
||||
}
|
||||
int GetCurrentFreqMhz() override {
|
||||
LOG(FATAL) << "Unsupported platform";
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
static const char IntelVendorString[] = "GenuineIntel";
|
||||
static const char AMDVendorString[] = "AuthenticAMD";
|
||||
|
||||
} // namespace
|
||||
|
||||
// Only works for Linux on x86-64
|
||||
void X86FVTController::GetCPUId(int cpu, uint32_t eax, CPUIDResult* result) {
|
||||
constexpr size_t kCPUIDPathMax = 1024;
|
||||
char CPUIDPath[kCPUIDPathMax];
|
||||
snprintf(CPUIDPath, sizeof(CPUIDPath), "/dev/cpu/%d/cpuid", cpu);
|
||||
int fd = open(CPUIDPath, O_RDONLY);
|
||||
assert(fd >= 0);
|
||||
ssize_t byte_read = pread(fd, result, sizeof(*result), eax);
|
||||
if (byte_read != sizeof(*result)) {
|
||||
LOG(FATAL) << "CPUID " << std::hex << eax << "failed.";
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
std::string X86FVTController::CPUIDVendorStringUncached() {
|
||||
char buffer[12];
|
||||
CPUIDResult result;
|
||||
GetCPUId(0, 0, &result);
|
||||
memcpy(buffer + 0, &result.ebx, 4);
|
||||
memcpy(buffer + 4, &result.edx, 4);
|
||||
memcpy(buffer + 8, &result.ecx, 4);
|
||||
return std::string(buffer, sizeof(buffer));
|
||||
}
|
||||
|
||||
std::string X86FVTController::CPUIDVendorString() {
|
||||
static const std::string vendor_string = CPUIDVendorStringUncached();
|
||||
return vendor_string;
|
||||
}
|
||||
|
||||
std::unique_ptr<FVTController> FVTController::Create(int cpu) {
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
const std::string vendor_string = X86FVTController::CPUIDVendorString();
|
||||
#ifdef VENDORS_INTEL_PATH
|
||||
if (vendor_string == IntelVendorString) {
|
||||
return NewIntelFVTController(cpu);
|
||||
}
|
||||
#endif
|
||||
#ifdef VENDORS_AMD_PATH
|
||||
if (vendor_string == AMDVendorString) {
|
||||
return NewAMDFVTController(cpu);
|
||||
}
|
||||
#endif
|
||||
LOG(FATAL) << "Unsupported x86 vendor";
|
||||
return nullptr;
|
||||
#else
|
||||
return std::unique_ptr<FVTController>(new NonX86FVTController(cpu));
|
||||
#endif
|
||||
}
|
164
fvt_controller.h
Normal file
164
fvt_controller.h
Normal file
@@ -0,0 +1,164 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef FVT_CONTROLLER_
|
||||
#define FVT_CONTROLLER_
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
#include "log.h"
|
||||
#include "utils.h"
|
||||
|
||||
// Frequency, Voltage and Thermal (FVT) controller.
|
||||
class FVTController {
|
||||
public:
|
||||
static constexpr int kMinTurboMHz = 1000;
|
||||
|
||||
protected:
|
||||
explicit FVTController(int cpu) : cpu_(cpu) {
|
||||
ResetFrequencyMeter();
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~FVTController() {}
|
||||
|
||||
static std::unique_ptr<FVTController> Create(int cpu);
|
||||
|
||||
// Monitor per-cpu (or core) frequency control.
|
||||
void MonitorFrequency() {
|
||||
const double t = TimeInSeconds();
|
||||
const int f = GetCurrentFreqMhz();
|
||||
sum_mHz_ += (t - previous_sample_time_) * f;
|
||||
previous_sample_time_ = t;
|
||||
|
||||
const int mHz = GetCurrentFreqLimitMhz();
|
||||
if (mHz != max_mHz_) {
|
||||
LOG_EVERY_N_SECS(INFO, 10) << "Cpu: " << cpu_
|
||||
<< " max turbo frequency control changed to: " << mHz;
|
||||
max_mHz_ = mHz;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the current CPU frequency limit. Warning: do this to both threads of
|
||||
// HT pair. Requires 'mhz' multiple of 100, within legitimate range.
|
||||
virtual void SetCurrentFreqLimitMhz(int mhz) = 0;
|
||||
|
||||
// Returns the absolute maximum CPU frequency.
|
||||
virtual int GetAbsoluteFreqLimitMhz() = 0;
|
||||
|
||||
// Dont put much stock in this method, it's probably a lousy way to do things.
|
||||
int GetMeanFreqMhz() const {
|
||||
return sum_mHz_ / (previous_sample_time_ - t0_);
|
||||
}
|
||||
|
||||
int max_mHz() const { return max_mHz_; }
|
||||
|
||||
int limit_mHz() const { return limit_mhz_; }
|
||||
|
||||
// Returns true if automatic Power Management enabled.
|
||||
virtual bool PowerManaged() const = 0;
|
||||
|
||||
// Returns frequency, thermal, and voltage condition.
|
||||
virtual std::string FVT() = 0;
|
||||
|
||||
virtual std::string InterestingEnables() const = 0;
|
||||
|
||||
// TODO: separate this from FVT controller.
|
||||
virtual void ControlFastStringOps(bool enable) = 0;
|
||||
|
||||
protected:
|
||||
// Returns the current CPU frequency limit in MHz.
|
||||
virtual int GetCurrentFreqLimitMhz() = 0;
|
||||
|
||||
// Returns the current CPU frequency in MHz.
|
||||
virtual int GetCurrentFreqMhz() = 0;
|
||||
|
||||
void ResetFrequencyMeter() {
|
||||
t0_ = TimeInSeconds();
|
||||
previous_sample_time_ = t0_;
|
||||
sum_mHz_ = 0.0;
|
||||
}
|
||||
|
||||
const int cpu_;
|
||||
double t0_ = 0.0;
|
||||
int limit_mhz_ = 0; // const after init
|
||||
int max_mHz_ = 0;
|
||||
double sum_mHz_ = 0.0;
|
||||
double previous_sample_time_ = 0.0;
|
||||
};
|
||||
|
||||
class X86FVTController : public FVTController {
|
||||
public:
|
||||
struct CPUIDResult {
|
||||
uint32_t eax;
|
||||
uint32_t ebx;
|
||||
uint32_t ecx;
|
||||
uint32_t edx;
|
||||
};
|
||||
|
||||
explicit X86FVTController(int cpu) : FVTController(cpu) {
|
||||
std::stringstream dev;
|
||||
dev << "/dev/cpu/" << cpu << "/msr";
|
||||
fd_ = open(dev.str().c_str(), O_RDWR);
|
||||
if (fd_ < 0) {
|
||||
LOG(ERROR) << "Cannot open: " << dev.str()
|
||||
<< " Running me as root?";
|
||||
}
|
||||
}
|
||||
~X86FVTController() override {
|
||||
if (fd_ >= 0) close(fd_);
|
||||
}
|
||||
|
||||
// Only works for Linux on x86-64
|
||||
static void GetCPUId(int cpu, uint32_t eax, CPUIDResult* result);
|
||||
|
||||
// Return the vendor string from CPUID
|
||||
static std::string CPUIDVendorString();
|
||||
|
||||
protected:
|
||||
uint64_t ReadMsr(uint32_t reg) const {
|
||||
if (fd_ < 0) return 0;
|
||||
uint64_t v = 0;
|
||||
int rc = pread(fd_, &v, sizeof(v), reg);
|
||||
if (rc != sizeof(v)) {
|
||||
LOG_EVERY_N_SECS(ERROR, 60) << "Unable to read cpu: " << cpu_
|
||||
<< " reg: " << std::hex << reg;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
void WriteMsr(uint32_t reg, uint64_t v) const {
|
||||
if (fd_ < 0) return;
|
||||
int rc = pwrite(fd_, &v, sizeof(v), reg);
|
||||
if (rc != sizeof(v)) {
|
||||
fprintf(stderr, "rc = %d sizeof(v) = %lu\n", rc, sizeof(v));
|
||||
LOG_EVERY_N_SECS(ERROR, 60) << "Unable to write cpu: " << cpu_
|
||||
<< " reg: " << std::hex << reg;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static std::string CPUIDVendorStringUncached();
|
||||
|
||||
int fd_ = -1;
|
||||
};
|
||||
|
||||
extern std::unique_ptr<FVTController> NewAMDFVTController(int cpu);
|
||||
extern std::unique_ptr<FVTController> NewIntelFVTController(int cpu);
|
||||
|
||||
#endif // FVT_CONTROLLER_
|
142
log.h
Normal file
142
log.h
Normal file
@@ -0,0 +1,142 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef LOG_H_
|
||||
#define LOG_H_
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
enum LOG_LEVEL {
|
||||
DEBUG,
|
||||
INFO,
|
||||
WARN,
|
||||
ERROR,
|
||||
FATAL,
|
||||
};
|
||||
|
||||
// TODO - Flag to filter above a given log level
|
||||
|
||||
// TODO
|
||||
// Make this more efficient. Eg. use:
|
||||
// LOG_IF_COND(xx) << yy;
|
||||
// becomes
|
||||
// for (condvar;COND;) Log(blah).stream() << yy;
|
||||
|
||||
#define LOG(X) Log(__FILE__, __LINE__, X).stream()
|
||||
|
||||
#define LOG_EVERY_N(X, N) \
|
||||
static std::atomic<uint64_t> __FILE__##__LINE__##_counter(0); \
|
||||
Log(__FILE__, __LINE__, X, __FILE__##__LINE__##_counter, N).stream()
|
||||
|
||||
#define LOG_EVERY_N_SECS(X, N) \
|
||||
static std::atomic<int64_t> __FILE__##__LINE__##_lasttime(0); \
|
||||
Log(__FILE__, __LINE__, X, __FILE__##__LINE__##_lasttime, N).stream()
|
||||
|
||||
// TODO
|
||||
// #define VLOG(x)
|
||||
|
||||
static LOG_LEVEL min_log_level = INFO;
|
||||
|
||||
class Log {
|
||||
public:
|
||||
Log(const char* file, int line, LOG_LEVEL lvl) : lvl_(lvl) {
|
||||
if (lvl < min_log_level) {
|
||||
skip_ = true;
|
||||
return;
|
||||
}
|
||||
Init(file, line);
|
||||
}
|
||||
// For LOG_EVERY_N:
|
||||
Log(const char* file, int line, LOG_LEVEL lvl, std::atomic<uint64_t>& cnt,
|
||||
int N)
|
||||
: lvl_(lvl) {
|
||||
if (lvl < min_log_level) {
|
||||
skip_ = true;
|
||||
return;
|
||||
}
|
||||
if ((++cnt % N) != 0) {
|
||||
skip_ = true;
|
||||
return;
|
||||
}
|
||||
Init(file, line);
|
||||
}
|
||||
// For LOG_EVERY_N_SECS:
|
||||
Log(const char* file, int line, LOG_LEVEL lvl, std::atomic<int64_t>& t, int N)
|
||||
: lvl_(lvl) {
|
||||
if (lvl < min_log_level) {
|
||||
skip_ = true;
|
||||
return;
|
||||
}
|
||||
int64_t now = time(nullptr);
|
||||
int64_t last = t;
|
||||
|
||||
if (now - last < N || !t.compare_exchange_strong(last, now)) {
|
||||
skip_ = true;
|
||||
return;
|
||||
}
|
||||
Init(file, line);
|
||||
}
|
||||
|
||||
~Log() {
|
||||
if (skip_) return;
|
||||
// You might prefer to direct errors to stderr, e.g.
|
||||
// (lvl_ < WARN ? std::cout : std::cerr) << os_.str();
|
||||
std::cout << os_.str() << std::endl;
|
||||
if (lvl_ == FATAL) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& stream() { return os_; }
|
||||
|
||||
std::ostream& operator<<(const std::string& s) {
|
||||
if (skip_) return os_;
|
||||
return os_ << s;
|
||||
}
|
||||
|
||||
private:
|
||||
void Init(const char* file, int line) {
|
||||
static const char l[] = {
|
||||
'D', 'I', 'W', 'E', 'F',
|
||||
};
|
||||
struct timeval tvs;
|
||||
struct tm tms;
|
||||
time_t t;
|
||||
char s[17];
|
||||
gettimeofday(&tvs, nullptr);
|
||||
t = tvs.tv_sec;
|
||||
gmtime_r(&t, &tms);
|
||||
strftime(s, sizeof(s), "%Y%m%d-%H%M%S.", &tms);
|
||||
char us[7];
|
||||
snprintf(us, sizeof(us), "%06ld", (long)tvs.tv_usec);
|
||||
|
||||
os_ << l[lvl_] << s << us << ' ' << pthread_self() << " " << file << ':'
|
||||
<< line << "] ";
|
||||
}
|
||||
|
||||
LOG_LEVEL lvl_;
|
||||
bool skip_ = false;
|
||||
std::stringstream os_;
|
||||
};
|
||||
|
||||
#endif // LOG_H_
|
1
third_party/farmhash
vendored
Submodule
1
third_party/farmhash
vendored
Submodule
Submodule third_party/farmhash added at 0d859a8118
75
utils.cc
Normal file
75
utils.cc
Normal file
@@ -0,0 +1,75 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
static const std::string host_name = []() {
|
||||
char host[256];
|
||||
gethostname(host, sizeof(host));
|
||||
const std::string h(host);
|
||||
size_t k = h.find('.');
|
||||
if (k == std::string::npos) return h;
|
||||
return h.substr(0, k);
|
||||
}();
|
||||
|
||||
double TimeInSeconds() {
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
return ((tv.tv_sec * 1e6) + tv.tv_usec) / 1e6;
|
||||
}
|
||||
|
||||
std::string Json(const std::string& field, int v) {
|
||||
return "\"" + field + "\": " + std::to_string(v);
|
||||
}
|
||||
|
||||
std::string Json(const std::string& field, uint64_t v) {
|
||||
return "\"" + field + "\": " + std::to_string(v);
|
||||
}
|
||||
|
||||
std::string Json(const std::string& field, double v) {
|
||||
return "\"" + field + "\": " + std::to_string(v);
|
||||
}
|
||||
|
||||
std::string JsonBool(const std::string& field, bool v) {
|
||||
return "\"" + field + "\": " + (v ? "true" : "false");
|
||||
}
|
||||
|
||||
std::string Json(const std::string& field, const std::string& v) {
|
||||
return "\"" + field + "\": \"" + v + "\"";
|
||||
}
|
||||
|
||||
std::string JsonRecord(const std::string& name, const std::string& v) {
|
||||
return "\"" + name + "\": { " + v + " }";
|
||||
}
|
||||
|
||||
// Emits null field.
|
||||
std::string JsonNull(const std::string& field) {
|
||||
return "\"" + field + "\": null";
|
||||
}
|
||||
|
||||
// Returns host and timestamp fields. ToDo: probably add a run id.
|
||||
std::string JTag() {
|
||||
const uint64_t t = TimeInSeconds() * 1e6;
|
||||
return Json("host", host_name) + ", " + Json("t_us", t);
|
||||
}
|
||||
|
||||
// Emits a run status record.
|
||||
std::string Jstat(const std::string& v) {
|
||||
return "{ " + JsonRecord("stat", v) + ", " + JTag() + " }";
|
||||
}
|
39
utils.h
Normal file
39
utils.h
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef UTILS_H_
|
||||
#define UTILS_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
double TimeInSeconds();
|
||||
|
||||
std::string Json(const std::string& field, int v);
|
||||
std::string Json(const std::string& field, uint64_t v);
|
||||
std::string Json(const std::string& field, double v);
|
||||
std::string JsonBool(const std::string& field, bool v);
|
||||
std::string Json(const std::string& field, const std::string& v);
|
||||
std::string JsonRecord(const std::string& name, const std::string& v);
|
||||
|
||||
// Emits null field.
|
||||
std::string JsonNull(const std::string& field);
|
||||
|
||||
// Returns host and timestamp fields. ToDo: probably add a run id.
|
||||
std::string JTag();
|
||||
|
||||
// Emits a run status record.
|
||||
std::string Jstat(const std::string& v);
|
||||
|
||||
#endif // UTILS_H_
|
154
vendors/intel/intel.cc
vendored
Normal file
154
vendors/intel/intel.cc
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Intel platform specific code
|
||||
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
|
||||
#include "../../fvt_controller.h"
|
||||
#include "../../log.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class IntelFVTController : public X86FVTController {
|
||||
public:
|
||||
explicit IntelFVTController(int cpu)
|
||||
: X86FVTController(cpu) {
|
||||
limit_mhz_ = GetAbsoluteFreqLimitMhzImpl();
|
||||
// Set initial Turbo frequency to max.
|
||||
SetCurrentMaxFreqMhzImpl(limit_mhz_);
|
||||
}
|
||||
|
||||
~IntelFVTController() override {
|
||||
// Upon exit, set Turbo frequency to max.
|
||||
SetCurrentMaxFreqMhzImpl(limit_mhz_);
|
||||
}
|
||||
|
||||
// Sets current maximum frequency. Warning: do this to both threads of HT
|
||||
// pair. Requires 'mhz' multiple of 100, within legitimate range.
|
||||
void SetCurrentFreqLimitMhz(int mhz) override {
|
||||
SetCurrentMaxFreqMhzImpl(mhz);
|
||||
}
|
||||
|
||||
// Returns absolute maximum CPU frequency.
|
||||
int GetAbsoluteFreqLimitMhz() override {
|
||||
return GetAbsoluteFreqLimitMhzImpl();
|
||||
}
|
||||
|
||||
// Returns true if automatic Power Management enabled.
|
||||
bool PowerManaged() const override {
|
||||
return ReadMsr(k_IA32_PM_ENABLE) & 0x1;
|
||||
}
|
||||
|
||||
// Returns frequency, thermal, and voltage condition.
|
||||
std::string FVT() override {
|
||||
constexpr double kVoltageScale = 1.0 / (1 << 13);
|
||||
const uint64_t v = ReadMsr(k_IA32_THERM_STATUS);
|
||||
const bool valid = (v >> 31) & 0x1;
|
||||
const int c = valid ? (v >> 16) & 0x7f : 0;
|
||||
const bool current_limit = (v >> 12) & 0x1;
|
||||
const bool power_limit = (v >> 10) & 0x1;
|
||||
const bool critical = (v >> 4) & 0x1;
|
||||
const bool proc_hot = v & 0x1; // AKA "Thermal Status"
|
||||
const uint64_t p = ReadMsr(k_IA32_PERF_STATUS);
|
||||
const double voltage = ((p >> 32) & 0xffff) * kVoltageScale;
|
||||
const int f = GetCurrentFreqMhz();
|
||||
std::stringstream s;
|
||||
s << (critical ? "Critical " : "")
|
||||
<< (proc_hot ? "ProcIsHot " : "")
|
||||
<< (current_limit ? "CurrentLimit " : "")
|
||||
<< (power_limit ? "PowerLimit " : "");
|
||||
return Json("f", f) + ", " + Json("voltage", voltage) + ", " +
|
||||
Json("margin", c) +
|
||||
(s.str().empty() ? "" : ", " + Json("pow_states", s.str()));
|
||||
}
|
||||
|
||||
std::string InterestingEnables() const override {
|
||||
const uint64_t v = ReadMsr(k_IA32_MISC_ENABLE);
|
||||
const bool fast_strings = v & 0x1;
|
||||
const bool auto_thermal_control = (v >> 3) & 0x1;
|
||||
const bool pm = PowerManaged();
|
||||
std::stringstream s;
|
||||
s << (fast_strings ? "FastStrings " : "")
|
||||
<< (auto_thermal_control ? "AutoThermalControl " : "")
|
||||
<< (pm ? "PowerManagement" : "");
|
||||
return s.str();
|
||||
}
|
||||
|
||||
// TODO: separate this from FVT controller.
|
||||
void ControlFastStringOps(bool enable) override {
|
||||
uint64_t v = ReadMsr(k_IA32_MISC_ENABLE);
|
||||
v = (v & ~0x1) | (enable & 0x1);
|
||||
WriteMsr(k_IA32_MISC_ENABLE, v);
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr int k_SEND_COMMAND = 0x150;
|
||||
static constexpr int k_IA32_PERF_STATUS = 0x198;
|
||||
static constexpr int k_IA32_PERF_CTL = 0x199;
|
||||
static constexpr int k_IA32_THERM_STATUS = 0x19c;
|
||||
static constexpr int k_IA32_MISC_ENABLE = 0x1a0;
|
||||
static constexpr int k_MSR_TURBO_RATIO_LIMIT = 0x1ad;
|
||||
static constexpr int k_IA32_PM_ENABLE = 0x770;
|
||||
|
||||
// Returns the current CPU frequency limit. This is not virtual so that we
|
||||
// can call this from constructor and destructor safely.
|
||||
int GetCurrentFreqLimitMhzImpl() {
|
||||
uint64_t v = ReadMsr(k_IA32_PERF_CTL);
|
||||
return ((v >> 8) & 0xff) * 100;
|
||||
}
|
||||
|
||||
int GetCurrentFreqLimitMhz() override {
|
||||
return GetCurrentFreqLimitMhzImpl();
|
||||
}
|
||||
|
||||
int GetCurrentFreqMhz() override {
|
||||
uint64_t v = ReadMsr(k_IA32_PERF_STATUS);
|
||||
return ((v >> 8) & 0xff) * 100;
|
||||
}
|
||||
|
||||
// This sets the current maximum CPU frequency. This is not virtual so that we
|
||||
// can call this from constructor and destructor safely.
|
||||
void SetCurrentMaxFreqMhzImpl(int mhz) {
|
||||
if (mhz == max_mHz_) return;
|
||||
if (PowerManaged()) {
|
||||
LOG_EVERY_N_SECS(ERROR, 10) << "Cpu: " << cpu_
|
||||
<< "Cannot set turbo freq while Power Management enabled!";
|
||||
}
|
||||
ResetFrequencyMeter();
|
||||
int hundreds = mhz / 100;
|
||||
assert(100 * hundreds == mhz);
|
||||
assert(mhz >= kMinTurboMHz);
|
||||
assert(mhz <= limit_mhz_);
|
||||
uint64_t v = hundreds << 8;
|
||||
WriteMsr(k_IA32_PERF_CTL, v);
|
||||
max_mHz_ = mhz;
|
||||
LOG_EVERY_N_SECS(INFO, 15) << "Set cpu: " << cpu_
|
||||
<< " max turbo freq to: " << mhz << " MHz";
|
||||
}
|
||||
|
||||
// Returns the absolute maximum frequency.
|
||||
int GetAbsoluteFreqLimitMhzImpl() {
|
||||
uint64_t v = ReadMsr(k_MSR_TURBO_RATIO_LIMIT);
|
||||
return (v & 0xff) * 100;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<FVTController> NewIntelFVTController(int cpu) {
|
||||
return std::unique_ptr<FVTController> (new IntelFVTController(cpu));
|
||||
}
|
Reference in New Issue
Block a user