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