mirror of
https://github.com/nlohmann/json.git
synced 2026-02-17 09:03:58 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5681e55da8 | ||
|
|
9f81beb5e2 | ||
|
|
c0d511ea50 | ||
|
|
1e99a0273f | ||
|
|
528bc96d7e | ||
|
|
1c98ce869c | ||
|
|
6df60b0448 | ||
|
|
272ebdc900 | ||
|
|
79a9d00e15 | ||
|
|
a4d13c92ba | ||
|
|
60bba02cc6 |
@@ -1,30 +0,0 @@
|
||||
version: 2
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: debian:stretch
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
- run:
|
||||
name: Install sudo
|
||||
command: 'apt-get update && apt-get install -y sudo && rm -rf /var/lib/apt/lists/*'
|
||||
- run:
|
||||
name: Install GCC
|
||||
command: 'apt-get update && apt-get install -y gcc g++'
|
||||
- run:
|
||||
name: Install CMake
|
||||
command: 'apt-get update && sudo apt-get install -y cmake'
|
||||
- run:
|
||||
name: Create build files
|
||||
command: 'mkdir build ; cd build ; cmake ..'
|
||||
- run:
|
||||
name: Versions
|
||||
command: 'g++ --version ; uname -a'
|
||||
- run:
|
||||
name: Compile
|
||||
command: 'cmake --build build'
|
||||
- run:
|
||||
name: Execute test suite
|
||||
command: 'cd build ; ctest -j 2'
|
||||
26
.clang-tidy
26
.clang-tidy
@@ -1,26 +0,0 @@
|
||||
Checks: '-*,
|
||||
bugprone-*,
|
||||
cert-*,
|
||||
clang-analyzer-*,
|
||||
google-*,
|
||||
-google-runtime-references,
|
||||
-google-explicit-constructor,
|
||||
hicpp-*,
|
||||
-hicpp-no-array-decay,
|
||||
-hicpp-uppercase-literal-suffix,
|
||||
-hicpp-explicit-conversions,
|
||||
misc-*,
|
||||
-misc-non-private-member-variables-in-classes,
|
||||
llvm-*,
|
||||
-llvm-header-guard,
|
||||
modernize-*,
|
||||
-modernize-use-trailing-return-type,
|
||||
performance-*,
|
||||
portability-*,
|
||||
readability-*,
|
||||
-readability-magic-numbers,
|
||||
-readability-uppercase-literal-suffix'
|
||||
|
||||
CheckOptions:
|
||||
- key: hicpp-special-member-functions.AllowSoleDefaultDtor
|
||||
value: 1
|
||||
82
.doozer.json
82
.doozer.json
@@ -1,82 +0,0 @@
|
||||
{
|
||||
"targets": {
|
||||
"raspbian-jessie": {
|
||||
"buildenv": "raspbian-jessie",
|
||||
"builddeps": ["build-essential", "wget"],
|
||||
"buildcmd": [
|
||||
"uname -a",
|
||||
"cat /etc/os-release",
|
||||
"g++ --version",
|
||||
"cd",
|
||||
"wget https://github.com/Kitware/CMake/releases/download/v3.14.0/cmake-3.14.0.tar.gz",
|
||||
"tar xfz cmake-3.14.0.tar.gz",
|
||||
"cd cmake-3.14.0",
|
||||
"./bootstrap",
|
||||
"make -j8",
|
||||
"cd",
|
||||
"mkdir build",
|
||||
"cd build",
|
||||
"../cmake-3.14.0/bin/cmake /project/repo/checkout",
|
||||
"make -j8",
|
||||
"../cmake-3.14.0/bin/ctest -VV -j4 --timeout 10000"
|
||||
]
|
||||
},
|
||||
"xenial-armhf": {
|
||||
"buildenv": "xenial-armhf",
|
||||
"builddeps": ["build-essential", "wget"],
|
||||
"buildcmd": [
|
||||
"uname -a",
|
||||
"lsb_release -a",
|
||||
"g++ --version",
|
||||
"cd",
|
||||
"wget --no-check-certificate https://github.com/Kitware/CMake/releases/download/v3.14.0/cmake-3.14.0.tar.gz",
|
||||
"tar xfz cmake-3.14.0.tar.gz",
|
||||
"cd cmake-3.14.0",
|
||||
"./bootstrap",
|
||||
"make -j8",
|
||||
"cd",
|
||||
"mkdir build",
|
||||
"cd build",
|
||||
"../cmake-3.14.0/bin/cmake /project/repo/checkout",
|
||||
"make -j8",
|
||||
"../cmake-3.14.0/bin/ctest -VV -j4 --timeout 10000"
|
||||
]
|
||||
},
|
||||
"fedora24-x86_64": {
|
||||
"buildenv": "fedora24-x86_64",
|
||||
"builddeps": ["cmake", "make", "gcc gcc-c++"],
|
||||
"buildcmd": [
|
||||
"uname -a",
|
||||
"cat /etc/fedora-release",
|
||||
"g++ --version",
|
||||
"cd",
|
||||
"mkdir build",
|
||||
"cd build",
|
||||
"cmake /project/repo/checkout",
|
||||
"make -j8",
|
||||
"ctest -VV -j8"
|
||||
]
|
||||
},
|
||||
"centos7-x86_64": {
|
||||
"buildenv": "centos7-x86_64",
|
||||
"builddeps": ["make", "wget", "gcc-c++"],
|
||||
"buildcmd": [
|
||||
"uname -a",
|
||||
"rpm -q centos-release",
|
||||
"g++ --version",
|
||||
"cd",
|
||||
"wget https://github.com/Kitware/CMake/releases/download/v3.14.0/cmake-3.14.0.tar.gz",
|
||||
"tar xfz cmake-3.14.0.tar.gz",
|
||||
"cd cmake-3.14.0",
|
||||
"./bootstrap",
|
||||
"make -j8",
|
||||
"cd",
|
||||
"mkdir build",
|
||||
"cd build",
|
||||
"../cmake-3.14.0/bin/cmake /project/repo/checkout",
|
||||
"make -j8",
|
||||
"../cmake-3.14.0/bin/ctest -VV -j8"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
6
.github/CODEOWNERS
vendored
6
.github/CODEOWNERS
vendored
@@ -1,6 +0,0 @@
|
||||
# JSON for Modern C++ has been originally written by Niels Lohmann.
|
||||
# Since 2013 over 140 contributors have helped to improve the library.
|
||||
# This CODEOWNERS file is only to make sure that @nlohmann is requsted
|
||||
# for a code review in case of a pull request.
|
||||
|
||||
* @nlohmann
|
||||
18
.github/CONTRIBUTING.md
vendored
18
.github/CONTRIBUTING.md
vendored
@@ -4,15 +4,15 @@
|
||||
|
||||
This project started as a little excuse to exercise some of the cool new C++11 features. Over time, people actually started to use the JSON library (yey!) and started to help improve it by proposing features, finding bugs, or even fixing my mistakes. I am really [thankful](https://github.com/nlohmann/json/blob/master/README.md#thanks) for this and try to keep track of all the helpers.
|
||||
|
||||
To make it as easy as possible for you to contribute and for me to keep an overview, here are a few guidelines which should help us avoid all kinds of unnecessary work or disappointment. And of course, this document is subject to discussion, so please [create an issue](https://github.com/nlohmann/json/issues/new/choose) or a pull request if you find a way to improve it!
|
||||
To make it as easy as possible for you to contribute and for me to keep an overview, here are a few guidelines which should help us avoid all kinds of unnecessary work or disappointment. And of course, this document is subject to discussion, so please [create an issue](https://github.com/nlohmann/json/issues/new) or a pull request if you find a way to improve it!
|
||||
|
||||
## Private reports
|
||||
|
||||
Usually, all issues are tracked publicly on [GitHub](https://github.com/nlohmann/json/issues). If you want to make a private report (e.g., for a vulnerability or to attach an example that is not meant to be published), please send an email to <mail@nlohmann.me>.
|
||||
Usually, all issues are tracked publicly on [Github](https://github.com/nlohmann/json/issues). If you want to make a private report (e.g., for a vulnerability or to attach an example that is not meant to be publisheed), please send an email to <mail@nlohmann.me>.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Please [create an issue](https://github.com/nlohmann/json/issues/new/choose), assuming one does not already exist, and describe your concern. Note you need a [GitHub account](https://github.com/signup/free) for this.
|
||||
Please [create an issue](https://github.com/nlohmann/json/issues/new), assuming one does not already exist, and describe your concern. Note you need a [GitHub account](https://github.com/signup/free) for this.
|
||||
|
||||
## Describe your issue
|
||||
|
||||
@@ -22,17 +22,15 @@ Clearly describe the issue:
|
||||
- If you propose a change or addition, try to give an **example** how the improved code could look like or how to use it.
|
||||
- If you found a compilation error, please tell us which **compiler** (version and operating system) you used and paste the (relevant part of) the error messages to the ticket.
|
||||
|
||||
Please stick to the provided issue templates ([bug report](https://github.com/nlohmann/json/blob/develop/.github/ISSUE_TEMPLATE/Bug_report.md), [feature request](https://github.com/nlohmann/json/blob/develop/.github/ISSUE_TEMPLATE/Feature_request.md), or [question](https://github.com/nlohmann/json/blob/develop/.github/ISSUE_TEMPLATE/question.md)) if possible.
|
||||
Please stick to the [issue template](https://github.com/nlohmann/json/blob/develop/.github/ISSUE_TEMPLATE.md) if possible.
|
||||
|
||||
## Files to change
|
||||
|
||||
:exclamation: Before you make any changes, note the single-header file [`single_include/nlohmann/json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp) is **generated** from the source files in the [`include/nlohmann` directory](https://github.com/nlohmann/json/tree/develop/include/nlohmann). Please **do not** edit file `single_include/nlohmann/json.hpp` directly, but change the `include/nlohmann` sources and regenerate file `single_include/nlohmann/json.hpp` by executing `make amalgamate`.
|
||||
There are currently two files which need to be edited:
|
||||
|
||||
To make changes, you need to edit the following files:
|
||||
1. [`src/json.hpp`](https://github.com/nlohmann/json/blob/master/src/json.hpp)
|
||||
|
||||
1. [`include/nlohmann/*`](https://github.com/nlohmann/json/tree/develop/include/nlohmann) - These files are the sources of the library. Before testing or creating a pull request, execute `make amalgamate` to regenerate `single_include/nlohmann/json.hpp`.
|
||||
|
||||
2. [`test/src/unit-*.cpp`](https://github.com/nlohmann/json/tree/develop/test/src) - These files contain the [doctest](https://github.com/onqtam/doctest) unit tests which currently cover [100 %](https://coveralls.io/github/nlohmann/json) of the library's code.
|
||||
2. [`test/src/unit-*.cpp`](https://github.com/nlohmann/json/tree/develop/test/src) - These files contain the [Catch](https://github.com/philsquared/Catch) unit tests which currently cover [100 %](https://coveralls.io/github/nlohmann/json) of the library's code.
|
||||
|
||||
If you add or change a feature, please also add a unit test to this file. The unit tests can be compiled and executed with
|
||||
|
||||
@@ -54,7 +52,7 @@ To make changes, you need to edit the following files:
|
||||
|
||||
## Please don't
|
||||
|
||||
- The C++11 support varies between different **compilers** and versions. Please note the [list of supported compilers](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers). Some compilers like GCC 4.7 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support. Please refrain from proposing changes that work around these compiler's limitations with `#ifdef`s or other means.
|
||||
- The C++11 support varies between different **compilers** and versions. Please note the [list of supported compilers](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers). Some compilers like GCC 4.8 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support. Please refrain from proposing changes that work around these compiler's limitations with `#ifdef`s or other means.
|
||||
- Specifically, I am aware of compilation problems with **Microsoft Visual Studio** (there even is an [issue label](https://github.com/nlohmann/json/issues?utf8=✓&q=label%3A%22visual+studio%22+) for these kind of bugs). I understand that even in 2016, complete C++11 support isn't there yet. But please also understand that I do not want to drop features or uglify the code just to make Microsoft's sub-standard compiler happy. The past has shown that there are ways to express the functionality such that the code compiles with the most recent MSVC - unfortunately, this is not the main objective of the project.
|
||||
- Please refrain from proposing changes that would **break [JSON](http://json.org) conformance**. If you propose a conformant extension of JSON to be supported by the library, please motivate this extension.
|
||||
- We shall not extend the library to **support comments**. There is quite some [controversy](https://www.reddit.com/r/programming/comments/4v6chu/why_json_doesnt_support_comments_douglas_crockford/) around this topic, and there were quite some [issues](https://github.com/nlohmann/json/issues/376) on this. We believe that JSON is fine without comments.
|
||||
|
||||
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
@@ -1 +0,0 @@
|
||||
custom: http://paypal.me/nlohmann
|
||||
@@ -1,11 +1,4 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: 'kind: bug'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
**Bug Report**
|
||||
|
||||
- What is the issue you have?
|
||||
|
||||
@@ -20,3 +13,10 @@ assignees: ''
|
||||
- Did you use a released version of the library or the version from the `develop` branch?
|
||||
|
||||
- If you experience a compilation error: can you [compile and run the unit tests](https://github.com/nlohmann/json#execute-unit-tests)?
|
||||
|
||||
|
||||
**Feature Request**
|
||||
|
||||
- Describe the feature in as much detail as possible.
|
||||
|
||||
- Include sample usage where appropriate.
|
||||
12
.github/ISSUE_TEMPLATE/Feature_request.md
vendored
12
.github/ISSUE_TEMPLATE/Feature_request.md
vendored
@@ -1,12 +0,0 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: 'kind: enhancement/improvement'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
- Describe the feature in as much detail as possible.
|
||||
|
||||
- Include sample usage where appropriate.
|
||||
16
.github/ISSUE_TEMPLATE/question.md
vendored
16
.github/ISSUE_TEMPLATE/question.md
vendored
@@ -1,16 +0,0 @@
|
||||
---
|
||||
name: Question
|
||||
about: Ask a question regarding the library.
|
||||
title: ''
|
||||
labels: 'kind: question'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
- Describe what you want to achieve.
|
||||
|
||||
- Describe what you tried.
|
||||
|
||||
- Describe which system (OS, compiler) you are using.
|
||||
|
||||
- Describe which version of the library you are using (release version, develop branch).
|
||||
5
.github/PULL_REQUEST_TEMPLATE.md
vendored
5
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -4,16 +4,13 @@
|
||||
|
||||
## Pull request checklist
|
||||
|
||||
Read the [Contribution Guidelines](https://github.com/nlohmann/json/blob/develop/.github/CONTRIBUTING.md) for detailed information.
|
||||
|
||||
- [ ] Changes are described in the pull request, or an [existing issue is referenced](https://github.com/nlohmann/json/issues).
|
||||
- [ ] The test suite [compiles and runs](https://github.com/nlohmann/json/blob/develop/README.md#execute-unit-tests) without error.
|
||||
- [ ] [Code coverage](https://coveralls.io/github/nlohmann/json) is 100%. Test cases can be added by editing the [test suite](https://github.com/nlohmann/json/tree/develop/test/src).
|
||||
- [ ] The source code is amalgamated; that is, after making changes to the sources in the `include/nlohmann` directory, run `make amalgamate` to create the single-header file `single_include/nlohmann/json.hpp`. The whole process is described [here](https://github.com/nlohmann/json/blob/develop/.github/CONTRIBUTING.md#files-to-change).
|
||||
|
||||
## Please don't
|
||||
|
||||
- The C++11 support varies between different **compilers** and versions. Please note the [list of supported compilers](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers). Some compilers like GCC 4.7 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support. Please refrain from proposing changes that work around these compiler's limitations with `#ifdef`s or other means.
|
||||
- The C++11 support varies between different **compilers** and versions. Please note the [list of supported compilers](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers). Some compilers like GCC 4.8 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support. Please refrain from proposing changes that work around these compiler's limitations with `#ifdef`s or other means.
|
||||
- Specifically, I am aware of compilation problems with **Microsoft Visual Studio** (there even is an [issue label](https://github.com/nlohmann/json/issues?utf8=✓&q=label%3A%22visual+studio%22+) for these kind of bugs). I understand that even in 2016, complete C++11 support isn't there yet. But please also understand that I do not want to drop features or uglify the code just to make Microsoft's sub-standard compiler happy. The past has shown that there are ways to express the functionality such that the code compiles with the most recent MSVC - unfortunately, this is not the main objective of the project.
|
||||
- Please refrain from proposing changes that would **break [JSON](http://json.org) conformance**. If you propose a conformant extension of JSON to be supported by the library, please motivate this extension.
|
||||
- Please do not open pull requests that address **multiple issues**.
|
||||
|
||||
5
.github/SECURITY.md
vendored
5
.github/SECURITY.md
vendored
@@ -1,5 +0,0 @@
|
||||
# Security Policy
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Usually, all issues are tracked publicly on [GitHub](https://github.com/nlohmann/json/issues). If you want to make a private report (e.g., for a vulnerability or to attach an example that is not meant to be published), please send an email to <mail@nlohmann.me>. You can use [this key](https://keybase.io/nlohmann/pgp_keys.asc?fingerprint=797167ae41c0a6d9232e48457f3cea63ae251b69) for encryption.
|
||||
19
.github/workflows/ccpp.yml
vendored
19
.github/workflows/ccpp.yml
vendored
@@ -1,19 +0,0 @@
|
||||
name: C/C++ CI
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: prepare
|
||||
run: mkdir build
|
||||
- name: cmake
|
||||
run: cd build ; cmake ..
|
||||
- name: build
|
||||
run: make -C build
|
||||
- name: test
|
||||
run: cd build ; ctest -j 10
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -10,7 +10,6 @@ fuzz-testing
|
||||
|
||||
build
|
||||
build_coverage
|
||||
clang_analyze_build
|
||||
|
||||
doc/xml
|
||||
doc/html
|
||||
@@ -22,4 +21,3 @@ benchmarks/files/numbers/*.json
|
||||
cmake-build-debug
|
||||
|
||||
test/test-*
|
||||
/.vs
|
||||
|
||||
127
.travis.yml
127
.travis.yml
@@ -43,15 +43,12 @@ matrix:
|
||||
- os: linux
|
||||
compiler: clang
|
||||
env:
|
||||
- COMPILER=clang++-7
|
||||
- COMPILER=clang++-5.0
|
||||
- CMAKE_OPTIONS=-DJSON_Sanitizer=ON
|
||||
- UBSAN_OPTIONS=print_stacktrace=1,suppressions=$(pwd)/test/src/UBSAN.supp
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-7']
|
||||
packages: ['g++-6', 'clang-7', 'ninja-build']
|
||||
before_script:
|
||||
- export PATH=$PATH:/usr/lib/llvm-7/bin
|
||||
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-5.0']
|
||||
packages: ['g++-6', 'clang-5.0', 'ninja-build']
|
||||
|
||||
# cppcheck
|
||||
- os: linux
|
||||
@@ -77,20 +74,6 @@ matrix:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-4.9', 'ninja-build']
|
||||
|
||||
# check amalgamation
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
env:
|
||||
- COMPILER=g++-4.9
|
||||
- SPECIAL=amalgamation
|
||||
- MULTIPLE_HEADERS=ON
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-4.9', 'astyle', 'ninja-build']
|
||||
after_success:
|
||||
- make check-amalgamation
|
||||
|
||||
# Coveralls (http://gronlier.fr/blog/2015/01/adding-code-coverage-to-your-c-project/)
|
||||
|
||||
- os: linux
|
||||
@@ -102,11 +85,10 @@ matrix:
|
||||
before_script:
|
||||
- pip install --user cpp-coveralls
|
||||
after_success:
|
||||
- coveralls --build-root test --include include/nlohmann --gcov 'gcov-4.9' --gcov-options '\-lp'
|
||||
- coveralls --build-root test --include src --gcov 'gcov-4.9' --gcov-options '\-lp'
|
||||
env:
|
||||
- COMPILER=g++-4.9
|
||||
- CMAKE_OPTIONS=-DJSON_Coverage=ON
|
||||
- MULTIPLE_HEADERS=ON
|
||||
|
||||
# Coverity (only for branch coverity_scan)
|
||||
|
||||
@@ -131,6 +113,21 @@ matrix:
|
||||
|
||||
# OSX / Clang
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode6.4
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode7.3
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode8
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode8.1
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode8.2
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode8.3
|
||||
|
||||
@@ -143,31 +140,8 @@ matrix:
|
||||
- os: osx
|
||||
osx_image: xcode9.2
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode9.3
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode9.4
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode10
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode10.1
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode10.2
|
||||
|
||||
# Linux / GCC
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
env: COMPILER=g++-4.8
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-4.8', 'ninja-build']
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
env: COMPILER=g++-4.9
|
||||
@@ -200,31 +174,15 @@ matrix:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-7', 'ninja-build']
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
env: COMPILER=g++-8
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-8', 'ninja-build']
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
env: COMPILER=g++-9
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-9', 'ninja-build']
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
env:
|
||||
- COMPILER=g++-9
|
||||
- CXXFLAGS=-std=c++2a
|
||||
- COMPILER=g++-7
|
||||
- CXXFLAGS=-std=c++17
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-9', 'ninja-build']
|
||||
packages: ['g++-7', 'ninja-build']
|
||||
|
||||
# Linux / Clang
|
||||
|
||||
@@ -284,31 +242,15 @@ matrix:
|
||||
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-5.0']
|
||||
packages: ['g++-6', 'clang-5.0', 'ninja-build']
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
env: COMPILER=clang++-6.0
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-6.0']
|
||||
packages: ['g++-6', 'clang-6.0', 'ninja-build']
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
env: COMPILER=clang++-7
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-7']
|
||||
packages: ['g++-6', 'clang-7', 'ninja-build']
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
env:
|
||||
- COMPILER=clang++-7
|
||||
- COMPILER=clang++-5.0
|
||||
- CXXFLAGS=-std=c++1z
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-7']
|
||||
packages: ['g++-6', 'clang-7', 'ninja-build']
|
||||
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-5.0']
|
||||
packages: ['g++-6', 'clang-5.0', 'ninja-build']
|
||||
|
||||
################
|
||||
# build script #
|
||||
@@ -320,14 +262,11 @@ script:
|
||||
if [[ (-x $(which brew)) ]]; then
|
||||
brew update
|
||||
brew install cmake ninja
|
||||
brew upgrade cmake
|
||||
cmake --version
|
||||
fi
|
||||
|
||||
# make sure CXX is correctly set
|
||||
- if [[ "${COMPILER}" != "" ]]; then export CXX=${COMPILER}; fi
|
||||
# by default, use the single-header version
|
||||
- if [[ "${MULTIPLE_HEADERS}" == "" ]]; then export MULTIPLE_HEADERS=OFF; fi
|
||||
|
||||
# show OS/compiler version
|
||||
- uname -a
|
||||
@@ -335,14 +274,14 @@ script:
|
||||
|
||||
# compile and execute unit tests
|
||||
- mkdir -p build && cd build
|
||||
- cmake .. ${CMAKE_OPTIONS} -DJSON_MultipleHeaders=${MULTIPLE_HEADERS} -GNinja && cmake --build . --config Release
|
||||
- ctest -C Release --timeout 2700 -V -j
|
||||
- cmake .. ${CMAKE_OPTIONS} -GNinja && cmake --build . --config Release
|
||||
- ctest -C Release -V -j
|
||||
- cd ..
|
||||
|
||||
# check if homebrew works (only checks develop branch)
|
||||
- if [ `which brew` ]; then
|
||||
brew update ;
|
||||
brew tap nlohmann/json ;
|
||||
brew install nlohmann_json --HEAD ;
|
||||
brew test nlohmann_json ;
|
||||
# check if homebrew works (only checks develop branch)
|
||||
- if [ `which brew` ]; then
|
||||
brew update ;
|
||||
brew tap nlohmann/json ;
|
||||
brew install nlohmann_json --HEAD ;
|
||||
brew test nlohmann_json ;
|
||||
fi
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"checkRunSettings": {
|
||||
"vulnerableCheckRunConclusionLevel": "failure"
|
||||
},
|
||||
"issueSettings": {
|
||||
"minSeverityLevel": "LOW"
|
||||
}
|
||||
}
|
||||
107
CMakeLists.txt
107
CMakeLists.txt
@@ -1,78 +1,55 @@
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
cmake_minimum_required(VERSION 3.0.0)
|
||||
|
||||
##
|
||||
## PROJECT
|
||||
## name and version
|
||||
##
|
||||
project(nlohmann_json VERSION 3.7.3 LANGUAGES CXX)
|
||||
|
||||
##
|
||||
## INCLUDE
|
||||
##
|
||||
##
|
||||
include(ExternalProject)
|
||||
project(nlohmann_json VERSION 3.0.1 LANGUAGES CXX)
|
||||
|
||||
##
|
||||
## OPTIONS
|
||||
##
|
||||
option(JSON_BuildTests "Build the unit tests when BUILD_TESTING is enabled." ON)
|
||||
option(JSON_Install "Install CMake targets during install step." ON)
|
||||
option(JSON_MultipleHeaders "Use non-amalgamated version of the library." OFF)
|
||||
|
||||
##
|
||||
## CONFIGURATION
|
||||
##
|
||||
include(GNUInstallDirs)
|
||||
|
||||
set(NLOHMANN_JSON_TARGET_NAME ${PROJECT_NAME})
|
||||
set(NLOHMANN_JSON_CONFIG_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" CACHE INTERNAL "")
|
||||
set(NLOHMANN_JSON_INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
set(NLOHMANN_JSON_SOURCE_DIR "src/")
|
||||
set(NLOHMANN_JSON_CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}")
|
||||
set(NLOHMANN_JSON_INCLUDE_INSTALL_DIR "include")
|
||||
set(NLOHMANN_JSON_HEADER_INSTALL_DIR "${NLOHMANN_JSON_INCLUDE_INSTALL_DIR}/nlohmann")
|
||||
set(NLOHMANN_JSON_TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
|
||||
set(NLOHMANN_JSON_CMAKE_CONFIG_TEMPLATE "cmake/config.cmake.in")
|
||||
set(NLOHMANN_JSON_CMAKE_CONFIG_DIR "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
set(NLOHMANN_JSON_CMAKE_CONFIG_DIR "${CMAKE_CURRENT_BINARY_DIR}/cmake_config")
|
||||
set(NLOHMANN_JSON_CMAKE_VERSION_CONFIG_FILE "${NLOHMANN_JSON_CMAKE_CONFIG_DIR}/${PROJECT_NAME}ConfigVersion.cmake")
|
||||
set(NLOHMANN_JSON_CMAKE_PROJECT_CONFIG_FILE "${NLOHMANN_JSON_CMAKE_CONFIG_DIR}/${PROJECT_NAME}Config.cmake")
|
||||
set(NLOHMANN_JSON_CMAKE_PROJECT_TARGETS_FILE "${NLOHMANN_JSON_CMAKE_CONFIG_DIR}/${PROJECT_NAME}Targets.cmake")
|
||||
|
||||
if (JSON_MultipleHeaders)
|
||||
set(NLOHMANN_JSON_INCLUDE_BUILD_DIR "${PROJECT_SOURCE_DIR}/include/")
|
||||
message(STATUS "Using the multi-header code from ${NLOHMANN_JSON_INCLUDE_BUILD_DIR}")
|
||||
else()
|
||||
set(NLOHMANN_JSON_INCLUDE_BUILD_DIR "${PROJECT_SOURCE_DIR}/single_include/")
|
||||
message(STATUS "Using the single-header code from ${NLOHMANN_JSON_INCLUDE_BUILD_DIR}")
|
||||
endif()
|
||||
|
||||
##
|
||||
## TARGET
|
||||
## create target and add include path
|
||||
##
|
||||
add_library(${NLOHMANN_JSON_TARGET_NAME} INTERFACE)
|
||||
add_library(${PROJECT_NAME}::${NLOHMANN_JSON_TARGET_NAME} ALIAS ${NLOHMANN_JSON_TARGET_NAME})
|
||||
if (${CMAKE_VERSION} VERSION_LESS "3.8.0")
|
||||
target_compile_features(${NLOHMANN_JSON_TARGET_NAME} INTERFACE cxx_range_for)
|
||||
else()
|
||||
target_compile_features(${NLOHMANN_JSON_TARGET_NAME} INTERFACE cxx_std_11)
|
||||
endif()
|
||||
|
||||
target_include_directories(
|
||||
${NLOHMANN_JSON_TARGET_NAME}
|
||||
INTERFACE
|
||||
$<BUILD_INTERFACE:${NLOHMANN_JSON_INCLUDE_BUILD_DIR}>
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>
|
||||
$<INSTALL_INTERFACE:include>
|
||||
)
|
||||
|
||||
## add debug view definition file for msvc (natvis)
|
||||
if (MSVC)
|
||||
## add debug view defintion file for msvc (natvis) [cmake <= 3.2.2 does not support export of source files]
|
||||
if (MSVC AND CMAKE_VERSION VERSION_GREATER "3.2.2")
|
||||
set(NLOHMANN_ADD_NATVIS TRUE)
|
||||
set(NLOHMANN_NATVIS_FILE "nlohmann_json.natvis")
|
||||
target_sources(
|
||||
${NLOHMANN_JSON_TARGET_NAME}
|
||||
INTERFACE
|
||||
${NLOHMANN_JSON_TARGET_NAME}
|
||||
INTERFACE
|
||||
$<INSTALL_INTERFACE:${NLOHMANN_NATVIS_FILE}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${NLOHMANN_NATVIS_FILE}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${NLOHMANN_NATVIS_FILE}>
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
##
|
||||
## TESTS
|
||||
## create and configure the unit test target
|
||||
@@ -81,6 +58,7 @@ include(CTest) #adds option BUILD_TESTING (default ON)
|
||||
|
||||
if(BUILD_TESTING AND JSON_BuildTests)
|
||||
enable_testing()
|
||||
include_directories(${NLOHMANN_JSON_SOURCE_DIR})
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
@@ -92,40 +70,31 @@ include(CMakePackageConfigHelpers)
|
||||
write_basic_package_version_file(
|
||||
${NLOHMANN_JSON_CMAKE_VERSION_CONFIG_FILE} COMPATIBILITY SameMajorVersion
|
||||
)
|
||||
configure_file(
|
||||
configure_package_config_file(
|
||||
${NLOHMANN_JSON_CMAKE_CONFIG_TEMPLATE}
|
||||
${NLOHMANN_JSON_CMAKE_PROJECT_CONFIG_FILE}
|
||||
@ONLY
|
||||
INSTALL_DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR}
|
||||
)
|
||||
|
||||
if(JSON_Install)
|
||||
install(
|
||||
DIRECTORY ${NLOHMANN_JSON_SOURCE_DIR}
|
||||
DESTINATION ${NLOHMANN_JSON_HEADER_INSTALL_DIR}
|
||||
)
|
||||
install(
|
||||
FILES ${NLOHMANN_JSON_CMAKE_PROJECT_CONFIG_FILE} ${NLOHMANN_JSON_CMAKE_VERSION_CONFIG_FILE}
|
||||
DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR}
|
||||
)
|
||||
if (NLOHMANN_ADD_NATVIS)
|
||||
install(
|
||||
DIRECTORY ${NLOHMANN_JSON_INCLUDE_BUILD_DIR}
|
||||
DESTINATION ${NLOHMANN_JSON_INCLUDE_INSTALL_DIR}
|
||||
)
|
||||
install(
|
||||
FILES ${NLOHMANN_JSON_CMAKE_PROJECT_CONFIG_FILE} ${NLOHMANN_JSON_CMAKE_VERSION_CONFIG_FILE}
|
||||
DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR}
|
||||
)
|
||||
if (NLOHMANN_ADD_NATVIS)
|
||||
install(
|
||||
FILES ${NLOHMANN_NATVIS_FILE}
|
||||
DESTINATION .
|
||||
)
|
||||
endif()
|
||||
export(
|
||||
TARGETS ${NLOHMANN_JSON_TARGET_NAME}
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
FILE ${NLOHMANN_JSON_CMAKE_PROJECT_TARGETS_FILE}
|
||||
)
|
||||
install(
|
||||
TARGETS ${NLOHMANN_JSON_TARGET_NAME}
|
||||
EXPORT ${NLOHMANN_JSON_TARGETS_EXPORT_NAME}
|
||||
INCLUDES DESTINATION ${NLOHMANN_JSON_INCLUDE_INSTALL_DIR}
|
||||
)
|
||||
install(
|
||||
EXPORT ${NLOHMANN_JSON_TARGETS_EXPORT_NAME}
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR}
|
||||
)
|
||||
FILES ${NLOHMANN_NATVIS_FILE}
|
||||
DESTINATION .
|
||||
)
|
||||
endif()
|
||||
install(
|
||||
TARGETS ${NLOHMANN_JSON_TARGET_NAME}
|
||||
EXPORT ${NLOHMANN_JSON_TARGETS_EXPORT_NAME}
|
||||
INCLUDES DESTINATION ${NLOHMANN_JSON_INCLUDE_INSTALL_DIR}
|
||||
)
|
||||
install(
|
||||
EXPORT ${NLOHMANN_JSON_TARGETS_EXPORT_NAME}
|
||||
DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR}
|
||||
)
|
||||
|
||||
928
ChangeLog.md
928
ChangeLog.md
@@ -1,929 +1,6 @@
|
||||
# Change Log
|
||||
All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [v3.7.3](https://github.com/nlohmann/json/releases/tag/v3.7.3) (2019-11-17)
|
||||
[Full Changelog](https://github.com/nlohmann/json/compare/v3.7.2...v3.7.3)
|
||||
|
||||
- Project branches [\#1839](https://github.com/nlohmann/json/issues/1839)
|
||||
- Quadratic destruction complexity introduced in \#1436 [\#1837](https://github.com/nlohmann/json/issues/1837)
|
||||
- Trying to open a file [\#1814](https://github.com/nlohmann/json/issues/1814)
|
||||
- Comparing data type with value\_t::number\_integer fails [\#1783](https://github.com/nlohmann/json/issues/1783)
|
||||
- CMake version config file is architecture-dependent [\#1697](https://github.com/nlohmann/json/issues/1697)
|
||||
|
||||
- Fix quadratic destruction complexity [\#1838](https://github.com/nlohmann/json/pull/1838) ([nickaein](https://github.com/nickaein))
|
||||
|
||||
## [v3.7.2](https://github.com/nlohmann/json/releases/tag/v3.7.2) (2019-11-10)
|
||||
[Full Changelog](https://github.com/nlohmann/json/compare/v3.7.1...v3.7.2)
|
||||
|
||||
- Segmentation fault in destructor in case of large inputs [\#1835](https://github.com/nlohmann/json/issues/1835)
|
||||
- type\_name\(\) is not consistent with type\(\) [\#1833](https://github.com/nlohmann/json/issues/1833)
|
||||
- json::parse is not a member [\#1832](https://github.com/nlohmann/json/issues/1832)
|
||||
- How do you deal with json\* ? [\#1829](https://github.com/nlohmann/json/issues/1829)
|
||||
- Combined find\_package/add\_subdirectory not linking libraries [\#1771](https://github.com/nlohmann/json/issues/1771)
|
||||
- example code for ifstream reading a json file results in no operator error [\#1766](https://github.com/nlohmann/json/issues/1766)
|
||||
- Warning: unsequenced modification and access to 'range' [\#1674](https://github.com/nlohmann/json/issues/1674)
|
||||
- Segmentation fault \(stack overflow\) due to unbounded recursion [\#1419](https://github.com/nlohmann/json/issues/1419)
|
||||
- Stack-overflow \(OSS-Fuzz 4234\) [\#832](https://github.com/nlohmann/json/issues/832)
|
||||
|
||||
- Configure WhiteSource Bolt for GitHub [\#1830](https://github.com/nlohmann/json/pull/1830) ([whitesource-bolt-for-github[bot]](https://github.com/apps/whitesource-bolt-for-github))
|
||||
- Prevent stackoverflow caused by recursive deconstruction [\#1436](https://github.com/nlohmann/json/pull/1436) ([nickaein](https://github.com/nickaein))
|
||||
|
||||
## [v3.7.1](https://github.com/nlohmann/json/releases/tag/v3.7.1) (2019-11-06)
|
||||
[Full Changelog](https://github.com/nlohmann/json/compare/v3.7.0...v3.7.1)
|
||||
|
||||
- std::is\_constructible is always true with tuple [\#1825](https://github.com/nlohmann/json/issues/1825)
|
||||
- Can't compile from\_json\(std::valarray\<T\>\). [\#1824](https://github.com/nlohmann/json/issues/1824)
|
||||
- json class should have a get\_or member function [\#1823](https://github.com/nlohmann/json/issues/1823)
|
||||
- NLOHMANN\_JSON\_SERIALIZE\_ENUM macro capture's json objects by value [\#1822](https://github.com/nlohmann/json/issues/1822)
|
||||
- Parse fails when number literals start with zero [\#1820](https://github.com/nlohmann/json/issues/1820)
|
||||
- Parsing string into json doesn't preserve the order correctly. [\#1817](https://github.com/nlohmann/json/issues/1817)
|
||||
- Weird behaviour of `contains` with `json\_pointer` [\#1815](https://github.com/nlohmann/json/issues/1815)
|
||||
- strange behaviour with json\_pointer and .contains\(\) [\#1811](https://github.com/nlohmann/json/issues/1811)
|
||||
- Can \#1695 be re-opened? [\#1808](https://github.com/nlohmann/json/issues/1808)
|
||||
- Merge two json objects [\#1807](https://github.com/nlohmann/json/issues/1807)
|
||||
- std::is\_constructible\<json, std::unordered\_map\<std::string, Data\>\> when to\_json not defined [\#1805](https://github.com/nlohmann/json/issues/1805)
|
||||
- Private data on parsing [\#1802](https://github.com/nlohmann/json/issues/1802)
|
||||
- Capturing Line and Position when querying [\#1800](https://github.com/nlohmann/json/issues/1800)
|
||||
- json error on parsing DBL\_MAX from string [\#1796](https://github.com/nlohmann/json/issues/1796)
|
||||
- De/Serialisation of vector of tupple object with nested obect need Help please [\#1794](https://github.com/nlohmann/json/issues/1794)
|
||||
- Output json is corrupted [\#1793](https://github.com/nlohmann/json/issues/1793)
|
||||
- variable name byte sometimes used as a \#define [\#1792](https://github.com/nlohmann/json/issues/1792)
|
||||
- Can't read json file [\#1791](https://github.com/nlohmann/json/issues/1791)
|
||||
- Problems with special German letters [\#1789](https://github.com/nlohmann/json/issues/1789)
|
||||
- Support for trailing commas [\#1787](https://github.com/nlohmann/json/issues/1787)
|
||||
- json\_pointer construction bug [\#1786](https://github.com/nlohmann/json/issues/1786)
|
||||
- Visual Studio 2017 warning [\#1784](https://github.com/nlohmann/json/issues/1784)
|
||||
- ciso646 header become obsolete [\#1782](https://github.com/nlohmann/json/issues/1782)
|
||||
- Migrate LGTM.com installation from OAuth to GitHub App [\#1781](https://github.com/nlohmann/json/issues/1781)
|
||||
- JSON comparison, contains and operator& [\#1778](https://github.com/nlohmann/json/issues/1778)
|
||||
- pass a json object to a class contructor adds an array around the object [\#1776](https://github.com/nlohmann/json/issues/1776)
|
||||
- 'Float' number\_float\_function\_t template parameter name conflicts with C '\#define Float float' [\#1775](https://github.com/nlohmann/json/issues/1775)
|
||||
- A weird building problem :-\( [\#1774](https://github.com/nlohmann/json/issues/1774)
|
||||
- What is this json\_ref? [\#1772](https://github.com/nlohmann/json/issues/1772)
|
||||
- Interoperability with other languages [\#1770](https://github.com/nlohmann/json/issues/1770)
|
||||
- Json dump [\#1768](https://github.com/nlohmann/json/issues/1768)
|
||||
- json\_pointer\<\>::back\(\) should be const [\#1764](https://github.com/nlohmann/json/issues/1764)
|
||||
- How to get value from array [\#1762](https://github.com/nlohmann/json/issues/1762)
|
||||
- Merge two jsons [\#1757](https://github.com/nlohmann/json/issues/1757)
|
||||
- Unable to locate nlohmann\_jsonConfig.cmake [\#1755](https://github.com/nlohmann/json/issues/1755)
|
||||
- json.hpp won;t compile VS2019 CLR/CLI app but does in console app [\#1754](https://github.com/nlohmann/json/issues/1754)
|
||||
- \[Nested Json Objects\] Segmentation fault [\#1753](https://github.com/nlohmann/json/issues/1753)
|
||||
- remove/replace assert with exceptions [\#1752](https://github.com/nlohmann/json/issues/1752)
|
||||
- Add array support for update\(\) function [\#1751](https://github.com/nlohmann/json/issues/1751)
|
||||
- Is there a reason the `get\_to` method is defined in `include/nlohmann/json.hpp` but not in `single\_include/nlohmann/json.hpp`? [\#1750](https://github.com/nlohmann/json/issues/1750)
|
||||
- how to validate json object before calling dump\(\) [\#1748](https://github.com/nlohmann/json/issues/1748)
|
||||
- Unable to invoke accessors on json objects in lldb [\#1745](https://github.com/nlohmann/json/issues/1745)
|
||||
- Escaping string before parsing [\#1743](https://github.com/nlohmann/json/issues/1743)
|
||||
- Construction in a member initializer list using curly braces is set as 'array' [\#1742](https://github.com/nlohmann/json/issues/1742)
|
||||
- Read a subkey from json object [\#1740](https://github.com/nlohmann/json/issues/1740)
|
||||
- Serialize vector of glm:vec2 [\#1739](https://github.com/nlohmann/json/issues/1739)
|
||||
- Support nlohmann::basic\_json::value with JSON\_NOEXCEPTION [\#1738](https://github.com/nlohmann/json/issues/1738)
|
||||
- how to know the parse is error [\#1737](https://github.com/nlohmann/json/issues/1737)
|
||||
- How to check if a given key exists in a JSON object [\#1736](https://github.com/nlohmann/json/issues/1736)
|
||||
- Allow The Colon Key-Value Delimiter To Have A Space Before It \[@ READ ONLY\] [\#1735](https://github.com/nlohmann/json/issues/1735)
|
||||
- Allow Tail { "Key": "Value" } Comma \[@ READ ONLY\] [\#1734](https://github.com/nlohmann/json/issues/1734)
|
||||
- No-throw json::value\(\) [\#1733](https://github.com/nlohmann/json/issues/1733)
|
||||
- JsonObject.dump\(\) [\#1732](https://github.com/nlohmann/json/issues/1732)
|
||||
- basic\_json has no member "parse" [\#1731](https://github.com/nlohmann/json/issues/1731)
|
||||
- Exception "type must be string, but is array" [\#1730](https://github.com/nlohmann/json/issues/1730)
|
||||
- json::contains usage to find a path [\#1727](https://github.com/nlohmann/json/issues/1727)
|
||||
- How to create JSON Object from my Structures of Data and Json File from that Object [\#1726](https://github.com/nlohmann/json/issues/1726)
|
||||
- please provide an API to read JSON from file directly. [\#1725](https://github.com/nlohmann/json/issues/1725)
|
||||
- How to modify a value stored at a key? [\#1723](https://github.com/nlohmann/json/issues/1723)
|
||||
- CMake not correctly finding the configuration package for 3.7.0 [\#1721](https://github.com/nlohmann/json/issues/1721)
|
||||
- name typo in the "spack package management" section of README.md [\#1720](https://github.com/nlohmann/json/issues/1720)
|
||||
- How to add json to another json? [\#1718](https://github.com/nlohmann/json/issues/1718)
|
||||
- How can I save json object in file in order? [\#1717](https://github.com/nlohmann/json/issues/1717)
|
||||
- json::parse\(\) ubsan regression with v3.7.0 [\#1716](https://github.com/nlohmann/json/issues/1716)
|
||||
- What I am doing wrong?!? [\#1714](https://github.com/nlohmann/json/issues/1714)
|
||||
- Potential memory leak detected by Valgrind [\#1713](https://github.com/nlohmann/json/issues/1713)
|
||||
- json::parse is not thread safe? [\#1712](https://github.com/nlohmann/json/issues/1712)
|
||||
- static analysis alarm by cppcheck [\#1711](https://github.com/nlohmann/json/issues/1711)
|
||||
- The compilation time is slow [\#1710](https://github.com/nlohmann/json/issues/1710)
|
||||
- not linking properly with cmake [\#1709](https://github.com/nlohmann/json/issues/1709)
|
||||
- Error in dump\(\) with int64\_t minimum value [\#1708](https://github.com/nlohmann/json/issues/1708)
|
||||
- Crash on trying to deserialize json string on 3ds homebrew [\#1707](https://github.com/nlohmann/json/issues/1707)
|
||||
- Can't compile VS2019. 13 Errors [\#1706](https://github.com/nlohmann/json/issues/1706)
|
||||
- find an object that matches the search criteria [\#1705](https://github.com/nlohmann/json/issues/1705)
|
||||
- IntelliSense goes crazy on VS2019 [\#1704](https://github.com/nlohmann/json/issues/1704)
|
||||
- Installing on Ubuntu 16.04 [\#1703](https://github.com/nlohmann/json/issues/1703)
|
||||
- Where is json::parse now? [\#1702](https://github.com/nlohmann/json/issues/1702)
|
||||
- Forward header should't be amalgamated [\#1700](https://github.com/nlohmann/json/issues/1700)
|
||||
- Json support for Cmake version 2.8.12 [\#1699](https://github.com/nlohmann/json/issues/1699)
|
||||
- Intruisive scientific notation when using .dump\(\); [\#1698](https://github.com/nlohmann/json/issues/1698)
|
||||
- Is there support for automatic serialization/deserialization? [\#1696](https://github.com/nlohmann/json/issues/1696)
|
||||
- on MSVC dump\(\) will hard crash for larger json [\#1693](https://github.com/nlohmann/json/issues/1693)
|
||||
- puzzled implicit conversions [\#1692](https://github.com/nlohmann/json/issues/1692)
|
||||
- Information: My project uses this awesome library [\#1691](https://github.com/nlohmann/json/issues/1691)
|
||||
- Consider listing files explicitly instead of using GLOB [\#1686](https://github.com/nlohmann/json/issues/1686)
|
||||
- Failing tests on MSVC with VS2019 15.9.13 x64 [\#1685](https://github.com/nlohmann/json/issues/1685)
|
||||
- Consider putting the user-defined literals in a namespace [\#1682](https://github.com/nlohmann/json/issues/1682)
|
||||
- Change from v2 to v3. Encoding with cp1252 [\#1680](https://github.com/nlohmann/json/issues/1680)
|
||||
- How to add Fifo\_map into json using Cmake [\#1679](https://github.com/nlohmann/json/issues/1679)
|
||||
- include.zip should contain meson.build [\#1672](https://github.com/nlohmann/json/issues/1672)
|
||||
- \[Question\] How do I parse JSON into custom types? [\#1669](https://github.com/nlohmann/json/issues/1669)
|
||||
- Binary \(0x05\) data type for BSON to JSON conversion [\#1668](https://github.com/nlohmann/json/issues/1668)
|
||||
- Possible to call dump from lldb? [\#1666](https://github.com/nlohmann/json/issues/1666)
|
||||
- Segmentation fault when linked with libunwind [\#1665](https://github.com/nlohmann/json/issues/1665)
|
||||
- Should I include single-header after my to\_json and from\_json custom functions declaration? Why not? [\#1663](https://github.com/nlohmann/json/issues/1663)
|
||||
- Errors/Warnings in VS 2019 when Including Header File [\#1659](https://github.com/nlohmann/json/issues/1659)
|
||||
- Return null object from object's const operator\[\] as well. [\#1658](https://github.com/nlohmann/json/issues/1658)
|
||||
- Can't stream json object in to std::basic\_stringstream\<wchar\_t\> [\#1656](https://github.com/nlohmann/json/issues/1656)
|
||||
- C2440 in vs2015 cannot convert from 'initializer-list' to nlohmann::basic\_json [\#1655](https://github.com/nlohmann/json/issues/1655)
|
||||
- Issues around get and pointers [\#1653](https://github.com/nlohmann/json/issues/1653)
|
||||
- Non-member operator== breaks enum \(de\)serialization [\#1647](https://github.com/nlohmann/json/issues/1647)
|
||||
- Valgrind: bytes in 1 blocks are definitely lost [\#1646](https://github.com/nlohmann/json/issues/1646)
|
||||
- Convenient way to make 'basic\_json' accept 'QString' as an key type as well? [\#1640](https://github.com/nlohmann/json/issues/1640)
|
||||
- mongodb: nan, inf [\#1599](https://github.com/nlohmann/json/issues/1599)
|
||||
- Error in adl\_serializer [\#1590](https://github.com/nlohmann/json/issues/1590)
|
||||
- Injecting class during serialization [\#1584](https://github.com/nlohmann/json/issues/1584)
|
||||
- output\_adapter not user extensible [\#1534](https://github.com/nlohmann/json/issues/1534)
|
||||
- Inclusion of nlohmann/json.hpp causes OS/ABI to change on Linux [\#1410](https://github.com/nlohmann/json/issues/1410)
|
||||
- Add library versioning using inline namespaces [\#1394](https://github.com/nlohmann/json/issues/1394)
|
||||
- CBOR byte string support [\#1129](https://github.com/nlohmann/json/issues/1129)
|
||||
- How to deserialize array with derived objects [\#716](https://github.com/nlohmann/json/issues/716)
|
||||
|
||||
- Add restriction for tuple specialization of to\_json [\#1826](https://github.com/nlohmann/json/pull/1826) ([cbegue](https://github.com/cbegue))
|
||||
- Fix for \#1647 [\#1821](https://github.com/nlohmann/json/pull/1821) ([AnthonyVH](https://github.com/AnthonyVH))
|
||||
- Fix issue \#1805 [\#1806](https://github.com/nlohmann/json/pull/1806) ([cbegue](https://github.com/cbegue))
|
||||
- Fix some spelling errors - mostly in comments & documentation. [\#1803](https://github.com/nlohmann/json/pull/1803) ([flopp](https://github.com/flopp))
|
||||
- Update Hedley to v11. [\#1799](https://github.com/nlohmann/json/pull/1799) ([nemequ](https://github.com/nemequ))
|
||||
- iteration\_proxy: Fix integer truncation from std::size\_t to int [\#1797](https://github.com/nlohmann/json/pull/1797) ([t-b](https://github.com/t-b))
|
||||
- appveyor.yml: Add MSVC 16 2019 support [\#1780](https://github.com/nlohmann/json/pull/1780) ([t-b](https://github.com/t-b))
|
||||
- test/CMakeLists.txt: Use an explicit list instead of GLOB [\#1779](https://github.com/nlohmann/json/pull/1779) ([t-b](https://github.com/t-b))
|
||||
- Make json\_pointer::back const \(resolves \#1764\) [\#1769](https://github.com/nlohmann/json/pull/1769) ([chris0x44](https://github.com/chris0x44))
|
||||
- did you mean 'serialization'? [\#1767](https://github.com/nlohmann/json/pull/1767) ([0xflotus](https://github.com/0xflotus))
|
||||
- Allow items\(\) to be used with custom string [\#1765](https://github.com/nlohmann/json/pull/1765) ([crazyjul](https://github.com/crazyjul))
|
||||
- Cppcheck fixes [\#1760](https://github.com/nlohmann/json/pull/1760) ([Xav83](https://github.com/Xav83))
|
||||
- Fix and add test's for SFINAE problem [\#1741](https://github.com/nlohmann/json/pull/1741) ([tete17](https://github.com/tete17))
|
||||
- Fix clang sanitizer invocation [\#1728](https://github.com/nlohmann/json/pull/1728) ([t-b](https://github.com/t-b))
|
||||
- Add gcc 9 and compile with experimental C++20 support [\#1724](https://github.com/nlohmann/json/pull/1724) ([t-b](https://github.com/t-b))
|
||||
- Fix int64 min issue [\#1722](https://github.com/nlohmann/json/pull/1722) ([t-b](https://github.com/t-b))
|
||||
- release: add singleinclude and meson.build to include.zip [\#1694](https://github.com/nlohmann/json/pull/1694) ([eli-schwartz](https://github.com/eli-schwartz))
|
||||
|
||||
## [v3.7.0](https://github.com/nlohmann/json/releases/tag/v3.7.0) (2019-07-28)
|
||||
[Full Changelog](https://github.com/nlohmann/json/compare/v3.6.1...v3.7.0)
|
||||
|
||||
- How can I retrieve uknown strings from json file in my C++ program. [\#1684](https://github.com/nlohmann/json/issues/1684)
|
||||
- contains\(\) is sometimes causing stack-based buffer overrun exceptions [\#1683](https://github.com/nlohmann/json/issues/1683)
|
||||
- How to deserialize arrays from json [\#1681](https://github.com/nlohmann/json/issues/1681)
|
||||
- Compilation failed in VS2015 [\#1678](https://github.com/nlohmann/json/issues/1678)
|
||||
- Why the compiled object file is so huge? [\#1677](https://github.com/nlohmann/json/issues/1677)
|
||||
- From Version 2.1.1 to 3.6.1 serialize std::set [\#1676](https://github.com/nlohmann/json/issues/1676)
|
||||
- Qt deprecation model halting compiltion [\#1675](https://github.com/nlohmann/json/issues/1675)
|
||||
- Build For Raspberry pi , Rapbery with new Compiler C++17 [\#1671](https://github.com/nlohmann/json/issues/1671)
|
||||
- Build from Raspberry pi [\#1667](https://github.com/nlohmann/json/issues/1667)
|
||||
- Can not translate map with integer key to dict string ? [\#1664](https://github.com/nlohmann/json/issues/1664)
|
||||
- Double type converts to scientific notation [\#1661](https://github.com/nlohmann/json/issues/1661)
|
||||
- Missing v3.6.1 tag on master branch [\#1657](https://github.com/nlohmann/json/issues/1657)
|
||||
- Support Fleese Binary Data Format [\#1654](https://github.com/nlohmann/json/issues/1654)
|
||||
- Suggestion: replace alternative tokens for !, && and || with their symbols [\#1652](https://github.com/nlohmann/json/issues/1652)
|
||||
- Build failure test-allocator.vcxproj [\#1651](https://github.com/nlohmann/json/issues/1651)
|
||||
- How to provide function json& to\_json\(\) which is similar as 'void to\_json\(json&j, const CObject& obj\)' ? [\#1650](https://github.com/nlohmann/json/issues/1650)
|
||||
- Can't throw exception when starting file is a number [\#1649](https://github.com/nlohmann/json/issues/1649)
|
||||
- to\_json / from\_json with nested type [\#1648](https://github.com/nlohmann/json/issues/1648)
|
||||
- How to create a json object from a std::string, created by j.dump? [\#1645](https://github.com/nlohmann/json/issues/1645)
|
||||
- Problem getting vector \(array\) of strings [\#1644](https://github.com/nlohmann/json/issues/1644)
|
||||
- json.hpp compilation issue with other typedefs with same name [\#1642](https://github.com/nlohmann/json/issues/1642)
|
||||
- nlohmann::adl\_serializer\<T,void\>::to\_json no matching overloaded function found [\#1641](https://github.com/nlohmann/json/issues/1641)
|
||||
- overwrite adl\_serializer\<bool, void\> to change behaviour [\#1638](https://github.com/nlohmann/json/issues/1638)
|
||||
- json.SelectToken\("Manufacturers.Products.Price"\); [\#1637](https://github.com/nlohmann/json/issues/1637)
|
||||
- Add json type as value [\#1636](https://github.com/nlohmann/json/issues/1636)
|
||||
- Unit conversion test error: conversion from 'nlohmann::json' to non-scalar type 'std::string\_view' requested [\#1634](https://github.com/nlohmann/json/issues/1634)
|
||||
- nlohmann VS JsonCpp by C++17 [\#1633](https://github.com/nlohmann/json/issues/1633)
|
||||
- To integrate an inline helper function that return type name as string [\#1632](https://github.com/nlohmann/json/issues/1632)
|
||||
- Return JSON as reference [\#1631](https://github.com/nlohmann/json/issues/1631)
|
||||
- Updating from an older version causes problems with assing a json object to a struct [\#1630](https://github.com/nlohmann/json/issues/1630)
|
||||
- Can without default constructor function for user defined classes when only to\_json is needed? [\#1629](https://github.com/nlohmann/json/issues/1629)
|
||||
- Compilation fails with clang 6.x-8.x in C++14 mode [\#1628](https://github.com/nlohmann/json/issues/1628)
|
||||
- Treating floating point as string [\#1627](https://github.com/nlohmann/json/issues/1627)
|
||||
- error parsing character å [\#1626](https://github.com/nlohmann/json/issues/1626)
|
||||
- \[Help\] How to Improve Json Output Performance with Large Json Arrays [\#1624](https://github.com/nlohmann/json/issues/1624)
|
||||
- Suggested link changes for reporting new issues \[blob/develop/REAME.md and blob/develop/.github/CONTRIBUTING.md\] [\#1623](https://github.com/nlohmann/json/issues/1623)
|
||||
- Broken link to issue template in CONTRIBUTING.md [\#1622](https://github.com/nlohmann/json/issues/1622)
|
||||
- Missing word in README.md file [\#1621](https://github.com/nlohmann/json/issues/1621)
|
||||
- Package manager instructions in README for brew is incorrect [\#1620](https://github.com/nlohmann/json/issues/1620)
|
||||
- Building with Visual Studio 2019 [\#1619](https://github.com/nlohmann/json/issues/1619)
|
||||
- Precedence of to\_json and builtin harmful [\#1617](https://github.com/nlohmann/json/issues/1617)
|
||||
- The type json is missing from the html documentation [\#1616](https://github.com/nlohmann/json/issues/1616)
|
||||
- variant is not support in Release 3.6.1? [\#1615](https://github.com/nlohmann/json/issues/1615)
|
||||
- Replace assert with throw for const operator\[\] [\#1614](https://github.com/nlohmann/json/issues/1614)
|
||||
- Memory Overhead is Too High \(10x or more\) [\#1613](https://github.com/nlohmann/json/issues/1613)
|
||||
- program crash everytime, when other data type incomming in json stream as expected [\#1612](https://github.com/nlohmann/json/issues/1612)
|
||||
- Improved Enum Support [\#1611](https://github.com/nlohmann/json/issues/1611)
|
||||
- is it possible convert json object back to stl container ? [\#1610](https://github.com/nlohmann/json/issues/1610)
|
||||
- Add C++17-like emplace.back\(\) for arrays. [\#1609](https://github.com/nlohmann/json/issues/1609)
|
||||
- is\_nothrow\_copy\_constructible fails for json::const\_iterator on MSVC2015 x86 Debug build [\#1608](https://github.com/nlohmann/json/issues/1608)
|
||||
- Reading and writing array elements [\#1607](https://github.com/nlohmann/json/issues/1607)
|
||||
- Converting json::value to int [\#1605](https://github.com/nlohmann/json/issues/1605)
|
||||
- I have a vector of keys and and a string of value and i want to create nested json array [\#1604](https://github.com/nlohmann/json/issues/1604)
|
||||
- In compatible JSON object from nlohmann::json to nohman::json - unexpected end of input; expected '\[', '{', or a literal [\#1603](https://github.com/nlohmann/json/issues/1603)
|
||||
- json parser crash if having a large number integer in message [\#1602](https://github.com/nlohmann/json/issues/1602)
|
||||
- Value method with undocumented throwing 302 exception [\#1601](https://github.com/nlohmann/json/issues/1601)
|
||||
- Accessing value with json pointer adds key if not existing [\#1600](https://github.com/nlohmann/json/issues/1600)
|
||||
- README.md broken link to project documentation [\#1597](https://github.com/nlohmann/json/issues/1597)
|
||||
- Random Kudos: Thanks for your work on this! [\#1596](https://github.com/nlohmann/json/issues/1596)
|
||||
- json::parse return value and errors [\#1595](https://github.com/nlohmann/json/issues/1595)
|
||||
- initializer list constructor makes curly brace initialization fragile [\#1594](https://github.com/nlohmann/json/issues/1594)
|
||||
- trying to log message for missing keyword, difference between \["foo"\] and at\("foo"\) [\#1593](https://github.com/nlohmann/json/issues/1593)
|
||||
- std::string and std::wstring `to\_json` [\#1592](https://github.com/nlohmann/json/issues/1592)
|
||||
- I have a C structure which I need to convert to a JSON. How do I do it? Haven't found proper examples so far. [\#1591](https://github.com/nlohmann/json/issues/1591)
|
||||
- dump\_escaped possible error ? [\#1589](https://github.com/nlohmann/json/issues/1589)
|
||||
- json::parse\(\) into a vector\<string\> results in unhandled exception [\#1587](https://github.com/nlohmann/json/issues/1587)
|
||||
- push\_back\(\)/emplace\_back\(\) on array invalidates pointers to existing array items [\#1586](https://github.com/nlohmann/json/issues/1586)
|
||||
- Getting nlohmann::detail::parse\_error on JSON generated by nlohmann::json not sure why [\#1583](https://github.com/nlohmann/json/issues/1583)
|
||||
- getting error terminate called after throwing an instance of 'std::domain\_error' what\(\): cannot use at\(\) with string [\#1582](https://github.com/nlohmann/json/issues/1582)
|
||||
- how i create json file [\#1581](https://github.com/nlohmann/json/issues/1581)
|
||||
- prevent rounding of double datatype values [\#1580](https://github.com/nlohmann/json/issues/1580)
|
||||
- Documentation Container Overview Doesn't Reference Const Methods [\#1579](https://github.com/nlohmann/json/issues/1579)
|
||||
- Writing an array into a nlohmann::json object [\#1578](https://github.com/nlohmann/json/issues/1578)
|
||||
- compilation error when using with another library [\#1577](https://github.com/nlohmann/json/issues/1577)
|
||||
- Homebrew on OSX doesn't install cmake config file [\#1576](https://github.com/nlohmann/json/issues/1576)
|
||||
- `unflatten` vs objects with number-ish keys [\#1575](https://github.com/nlohmann/json/issues/1575)
|
||||
- JSON Parse Out of Range Error [\#1574](https://github.com/nlohmann/json/issues/1574)
|
||||
- Integrating into existing CMake Project [\#1573](https://github.com/nlohmann/json/issues/1573)
|
||||
- A "thinner" source code tar as part of release? [\#1572](https://github.com/nlohmann/json/issues/1572)
|
||||
- conversion to std::string failed [\#1571](https://github.com/nlohmann/json/issues/1571)
|
||||
- jPtr operation does not throw [\#1569](https://github.com/nlohmann/json/issues/1569)
|
||||
- How to generate dll file for this project [\#1568](https://github.com/nlohmann/json/issues/1568)
|
||||
- how to pass variable data to json in c [\#1567](https://github.com/nlohmann/json/issues/1567)
|
||||
- I want to achieve an upgraded function. [\#1566](https://github.com/nlohmann/json/issues/1566)
|
||||
- How to determine the type of elements read from a JSON array? [\#1564](https://github.com/nlohmann/json/issues/1564)
|
||||
- try\_get\_to [\#1563](https://github.com/nlohmann/json/issues/1563)
|
||||
- example code compile error [\#1562](https://github.com/nlohmann/json/issues/1562)
|
||||
- How to iterate over nested json object [\#1561](https://github.com/nlohmann/json/issues/1561)
|
||||
- Build Option/Separate Function to Allow to Throw on Duplicate Keys [\#1560](https://github.com/nlohmann/json/issues/1560)
|
||||
- Compiler Switches -Weffc++ & -Wshadow are throwing errors [\#1558](https://github.com/nlohmann/json/issues/1558)
|
||||
- warning: use of the 'nodiscard' attribute is a C++17 extension [\#1557](https://github.com/nlohmann/json/issues/1557)
|
||||
- Import/Export compressed JSON files [\#1556](https://github.com/nlohmann/json/issues/1556)
|
||||
- GDB renderers for json library [\#1554](https://github.com/nlohmann/json/issues/1554)
|
||||
- Is it possible to construct a json string object from a binary buffer? [\#1553](https://github.com/nlohmann/json/issues/1553)
|
||||
- json objects in list [\#1552](https://github.com/nlohmann/json/issues/1552)
|
||||
- Matrix output [\#1550](https://github.com/nlohmann/json/issues/1550)
|
||||
- Using json merge\_patch on ordered non-alphanumeric datasets [\#1549](https://github.com/nlohmann/json/issues/1549)
|
||||
- Invalid parsed value for big integer [\#1548](https://github.com/nlohmann/json/issues/1548)
|
||||
- Integrating with android ndk issues. [\#1547](https://github.com/nlohmann/json/issues/1547)
|
||||
- add noexcept json::value\("key", default\) method variant? [\#1546](https://github.com/nlohmann/json/issues/1546)
|
||||
- Thank you! 🙌 [\#1545](https://github.com/nlohmann/json/issues/1545)
|
||||
- Output and input matrix [\#1544](https://github.com/nlohmann/json/issues/1544)
|
||||
- Add regression tests for MSVC [\#1543](https://github.com/nlohmann/json/issues/1543)
|
||||
- \[Help Needed!\] Season of Docs [\#1542](https://github.com/nlohmann/json/issues/1542)
|
||||
- program still abort\(\) or exit\(\) with try catch [\#1541](https://github.com/nlohmann/json/issues/1541)
|
||||
- Have a json::type\_error exception because of JSON object [\#1540](https://github.com/nlohmann/json/issues/1540)
|
||||
- Using versioned namespaces [\#1539](https://github.com/nlohmann/json/issues/1539)
|
||||
- Quoted numbers [\#1538](https://github.com/nlohmann/json/issues/1538)
|
||||
- Reading a JSON file into an object [\#1537](https://github.com/nlohmann/json/issues/1537)
|
||||
- Releases 3.6.0 and 3.6.1 don't build on conda / windows [\#1536](https://github.com/nlohmann/json/issues/1536)
|
||||
- \[Clang\] warning: use of the 'nodiscard' attribute is a C++17 extension \[-Wc++17-extensions\] [\#1535](https://github.com/nlohmann/json/issues/1535)
|
||||
- wchar\_t/std::wstring json can be created but not accessed [\#1533](https://github.com/nlohmann/json/issues/1533)
|
||||
- json stringify [\#1532](https://github.com/nlohmann/json/issues/1532)
|
||||
- How can I use std::string\_view as the json\_key to "operator \[\]" ? [\#1529](https://github.com/nlohmann/json/issues/1529)
|
||||
- How can I use it from gcc on RPI [\#1528](https://github.com/nlohmann/json/issues/1528)
|
||||
- std::pair treated as an array instead of key-value in `std::vector\<std::pair\<\>\>` [\#1520](https://github.com/nlohmann/json/issues/1520)
|
||||
- Excessive Memory Usage for Large Json File [\#1516](https://github.com/nlohmann/json/issues/1516)
|
||||
- SAX dumper [\#1512](https://github.com/nlohmann/json/issues/1512)
|
||||
- Conversion to user type containing a std::vector not working with documented approach [\#1511](https://github.com/nlohmann/json/issues/1511)
|
||||
- How to get position info or parser context with custom from\_json\(\) that may throw exceptions? [\#1508](https://github.com/nlohmann/json/issues/1508)
|
||||
- Inconsistent use of type alias. [\#1507](https://github.com/nlohmann/json/issues/1507)
|
||||
- Is there a current way to represent strings as json int? [\#1503](https://github.com/nlohmann/json/issues/1503)
|
||||
- Intermittent issues with loadJSON [\#1484](https://github.com/nlohmann/json/issues/1484)
|
||||
- use json construct std::string [\#1462](https://github.com/nlohmann/json/issues/1462)
|
||||
- JSON Creation [\#1461](https://github.com/nlohmann/json/issues/1461)
|
||||
- Substantial performance penalty caused by polymorphic input adapter [\#1457](https://github.com/nlohmann/json/issues/1457)
|
||||
- Null bytes in files are treated like EOF [\#1095](https://github.com/nlohmann/json/issues/1095)
|
||||
- Feature: to\_string\(const json& j\); [\#916](https://github.com/nlohmann/json/issues/916)
|
||||
|
||||
- Use GNUInstallDirs instead of hard-coded path. [\#1673](https://github.com/nlohmann/json/pull/1673) ([remyabel](https://github.com/remyabel))
|
||||
- Package Manager: MSYS2 \(pacman\) [\#1670](https://github.com/nlohmann/json/pull/1670) ([podsvirov](https://github.com/podsvirov))
|
||||
- Fix json.hpp compilation issue with other typedefs with same name \(Issue \#1642\) [\#1643](https://github.com/nlohmann/json/pull/1643) ([kevinlul](https://github.com/kevinlul))
|
||||
- Add explicit conversion from json to std::string\_view in conversion unit test [\#1639](https://github.com/nlohmann/json/pull/1639) ([taylorhoward92](https://github.com/taylorhoward92))
|
||||
- Minor fixes in docs [\#1625](https://github.com/nlohmann/json/pull/1625) ([nickaein](https://github.com/nickaein))
|
||||
- Fix broken links to documentation [\#1598](https://github.com/nlohmann/json/pull/1598) ([nickaein](https://github.com/nickaein))
|
||||
- Added to\_string and added basic tests [\#1585](https://github.com/nlohmann/json/pull/1585) ([Macr0Nerd](https://github.com/Macr0Nerd))
|
||||
- Regression tests for MSVC [\#1570](https://github.com/nlohmann/json/pull/1570) ([nickaein](https://github.com/nickaein))
|
||||
- Fix/1511 [\#1555](https://github.com/nlohmann/json/pull/1555) ([theodelrieu](https://github.com/theodelrieu))
|
||||
- Remove C++17 extension warning from clang; \#1535 [\#1551](https://github.com/nlohmann/json/pull/1551) ([heavywatal](https://github.com/heavywatal))
|
||||
- moved from Catch to doctest for unit tests [\#1439](https://github.com/nlohmann/json/pull/1439) ([onqtam](https://github.com/onqtam))
|
||||
|
||||
## [v3.6.1](https://github.com/nlohmann/json/releases/tag/v3.6.1) (2019-03-20)
|
||||
[Full Changelog](https://github.com/nlohmann/json/compare/v3.6.0...v3.6.1)
|
||||
|
||||
- Failed to build with \<Windows.h\> [\#1531](https://github.com/nlohmann/json/issues/1531)
|
||||
- Compiling 3.6.0 with GCC \> 7, array vs std::array \#590 is back [\#1530](https://github.com/nlohmann/json/issues/1530)
|
||||
- 3.6.0: warning: missing initializer for member 'std::array\<char, 9ul\>::\_M\_elems' \[-Wmissing-field-initializers\] [\#1527](https://github.com/nlohmann/json/issues/1527)
|
||||
- unable to parse json [\#1525](https://github.com/nlohmann/json/issues/1525)
|
||||
|
||||
## [v3.6.0](https://github.com/nlohmann/json/releases/tag/v3.6.0) (2019-03-19)
|
||||
[Full Changelog](https://github.com/nlohmann/json/compare/v3.5.0...v3.6.0)
|
||||
|
||||
- How can I turn a string of a json array into a json array? [\#1526](https://github.com/nlohmann/json/issues/1526)
|
||||
- Minor: missing a std:: namespace tag [\#1521](https://github.com/nlohmann/json/issues/1521)
|
||||
- how to precision to four decimal for double when use to\_json [\#1519](https://github.com/nlohmann/json/issues/1519)
|
||||
- error parse [\#1518](https://github.com/nlohmann/json/issues/1518)
|
||||
- Compile error: template argument deduction/substitution failed [\#1515](https://github.com/nlohmann/json/issues/1515)
|
||||
- Support for Comments [\#1513](https://github.com/nlohmann/json/issues/1513)
|
||||
- std::complex type [\#1510](https://github.com/nlohmann/json/issues/1510)
|
||||
- CBOR byte string support [\#1509](https://github.com/nlohmann/json/issues/1509)
|
||||
- Compilation error getting a std::pair\<\> on latest VS 2017 compiler [\#1506](https://github.com/nlohmann/json/issues/1506)
|
||||
- "Integration" section of documentation needs update? [\#1505](https://github.com/nlohmann/json/issues/1505)
|
||||
- Json object from string from a TCP socket [\#1504](https://github.com/nlohmann/json/issues/1504)
|
||||
- MSVC warning C4946 \("reinterpret\_cast used between related classes"\) compiling json.hpp [\#1502](https://github.com/nlohmann/json/issues/1502)
|
||||
- How to programmatically fill an n-th dimensional JSON object? [\#1501](https://github.com/nlohmann/json/issues/1501)
|
||||
- Error compiling with clang and `JSON\_NOEXCEPTION`: need to include `cstdlib` [\#1500](https://github.com/nlohmann/json/issues/1500)
|
||||
- The code compiles unsuccessfully with android-ndk-r10e [\#1499](https://github.com/nlohmann/json/issues/1499)
|
||||
- Cmake 3.1 in develop, when is it likely to make it into a stable release? [\#1498](https://github.com/nlohmann/json/issues/1498)
|
||||
- Repository is almost 450MB [\#1497](https://github.com/nlohmann/json/issues/1497)
|
||||
- Some Help please object inside array [\#1494](https://github.com/nlohmann/json/issues/1494)
|
||||
- How to get data into vector of user-defined type from a Json object [\#1493](https://github.com/nlohmann/json/issues/1493)
|
||||
- how to find subelement without loop [\#1490](https://github.com/nlohmann/json/issues/1490)
|
||||
- json to std::map [\#1487](https://github.com/nlohmann/json/issues/1487)
|
||||
- Type in README.md [\#1486](https://github.com/nlohmann/json/issues/1486)
|
||||
- Error in parsing and reading msgpack-lite [\#1485](https://github.com/nlohmann/json/issues/1485)
|
||||
- Compiling issues with libc 2.12 [\#1483](https://github.com/nlohmann/json/issues/1483)
|
||||
- How do I use reference or pointer binding values? [\#1482](https://github.com/nlohmann/json/issues/1482)
|
||||
- Compilation fails in MSVC with the Microsoft Language Extensions disabled [\#1481](https://github.com/nlohmann/json/issues/1481)
|
||||
- Functional visit [\#1480](https://github.com/nlohmann/json/issues/1480)
|
||||
- \[Question\] Unescaped dump [\#1479](https://github.com/nlohmann/json/issues/1479)
|
||||
- Some Help please [\#1478](https://github.com/nlohmann/json/issues/1478)
|
||||
- Global variables are stored within the JSON file, how do I declare them as global variables when I read them out in my C++ program? [\#1476](https://github.com/nlohmann/json/issues/1476)
|
||||
- Unable to modify one of the values within the JSON file, and save it [\#1475](https://github.com/nlohmann/json/issues/1475)
|
||||
- Documentation of parse function has two identical @pre causes [\#1473](https://github.com/nlohmann/json/issues/1473)
|
||||
- GCC 9.0 build failure [\#1472](https://github.com/nlohmann/json/issues/1472)
|
||||
- Can we have an `exists\(\)` method? [\#1471](https://github.com/nlohmann/json/issues/1471)
|
||||
- How to parse multi object json from file? [\#1470](https://github.com/nlohmann/json/issues/1470)
|
||||
- How to returns the name of the upper object? [\#1467](https://github.com/nlohmann/json/issues/1467)
|
||||
- Error: "tuple\_size" has already been declared in the current scope [\#1466](https://github.com/nlohmann/json/issues/1466)
|
||||
- Checking keys of two jsons against eachother [\#1465](https://github.com/nlohmann/json/issues/1465)
|
||||
- Disable installation when used as meson subproject [\#1463](https://github.com/nlohmann/json/issues/1463)
|
||||
- Unpack list of integers to a std::vector\<int\> [\#1460](https://github.com/nlohmann/json/issues/1460)
|
||||
- Implement DRY definition of JSON representation of a c++ class [\#1459](https://github.com/nlohmann/json/issues/1459)
|
||||
- json.exception.type\_error.305 with GCC 4.9 when using C++ {} initializer [\#1458](https://github.com/nlohmann/json/issues/1458)
|
||||
- API to convert an "uninitialized" json into an empty object or empty array [\#1456](https://github.com/nlohmann/json/issues/1456)
|
||||
- How to parse a vector of objects with const attributes [\#1453](https://github.com/nlohmann/json/issues/1453)
|
||||
- NLOHMANN\_JSON\_SERIALIZE\_ENUM potentially requires duplicate definitions [\#1450](https://github.com/nlohmann/json/issues/1450)
|
||||
- Question about making json object from file directory [\#1449](https://github.com/nlohmann/json/issues/1449)
|
||||
- .get\(\) throws error if used with userdefined structs in unordered\_map [\#1448](https://github.com/nlohmann/json/issues/1448)
|
||||
- Integer Overflow \(OSS-Fuzz 12506\) [\#1447](https://github.com/nlohmann/json/issues/1447)
|
||||
- If a string has too many invalid UTF-8 characters, json::dump attempts to index an array out of bounds. [\#1445](https://github.com/nlohmann/json/issues/1445)
|
||||
- Setting values of .JSON file [\#1444](https://github.com/nlohmann/json/issues/1444)
|
||||
- alias object\_t::key\_type in basic\_json [\#1442](https://github.com/nlohmann/json/issues/1442)
|
||||
- Latest Ubuntu package is 2.1.1 [\#1438](https://github.com/nlohmann/json/issues/1438)
|
||||
- lexer.hpp\(1363\) '\_snprintf': is not a member | Visualstudio 2017 [\#1437](https://github.com/nlohmann/json/issues/1437)
|
||||
- Static method invites inadvertent logic error. [\#1433](https://github.com/nlohmann/json/issues/1433)
|
||||
- EOS compilation produces "fatal error: 'nlohmann/json.hpp' file not found" [\#1432](https://github.com/nlohmann/json/issues/1432)
|
||||
- Support for bad commas [\#1429](https://github.com/nlohmann/json/issues/1429)
|
||||
- Please have one base exception class for all json exceptions [\#1427](https://github.com/nlohmann/json/issues/1427)
|
||||
- Compilation warning: 'tuple\_size' defined as a class template here but previously declared as a struct template [\#1426](https://github.com/nlohmann/json/issues/1426)
|
||||
- Which version can be used with GCC 4.8.2 ? [\#1424](https://github.com/nlohmann/json/issues/1424)
|
||||
- Ignore nullptr values on constructing json object from a container [\#1422](https://github.com/nlohmann/json/issues/1422)
|
||||
- Support for custom float precision via unquoted strings [\#1421](https://github.com/nlohmann/json/issues/1421)
|
||||
- It is possible to call `json::find` with a json\_pointer as argument. This causes runtime UB/crash. [\#1418](https://github.com/nlohmann/json/issues/1418)
|
||||
- Dump throwing exception [\#1416](https://github.com/nlohmann/json/issues/1416)
|
||||
- Build error [\#1415](https://github.com/nlohmann/json/issues/1415)
|
||||
- Append version to include.zip [\#1412](https://github.com/nlohmann/json/issues/1412)
|
||||
- error C2039: '\_snprintf': is not a member of 'std' - Windows [\#1408](https://github.com/nlohmann/json/issues/1408)
|
||||
- Deserializing to vector [\#1407](https://github.com/nlohmann/json/issues/1407)
|
||||
- Efficient way to set a `json` object as value into another `json` key [\#1406](https://github.com/nlohmann/json/issues/1406)
|
||||
- Document return value of parse\(\) when allow\_exceptions == false and parsing fails [\#1405](https://github.com/nlohmann/json/issues/1405)
|
||||
- Unexpected behaviour with structured binding [\#1404](https://github.com/nlohmann/json/issues/1404)
|
||||
- Which native types does get\<type\>\(\) allow? [\#1403](https://github.com/nlohmann/json/issues/1403)
|
||||
- Add something like Json::StaticString [\#1402](https://github.com/nlohmann/json/issues/1402)
|
||||
- -Wmismatched-tags in 3.5.0? [\#1401](https://github.com/nlohmann/json/issues/1401)
|
||||
- Coverity Scan reports an UNCAUGHT\_EXCEPT issue [\#1400](https://github.com/nlohmann/json/issues/1400)
|
||||
- fff [\#1399](https://github.com/nlohmann/json/issues/1399)
|
||||
- sorry this is not an issue, just a Question, How to change a key value in a file and save it ? [\#1398](https://github.com/nlohmann/json/issues/1398)
|
||||
- appveyor x64 builds appear to be using Win32 toolset [\#1374](https://github.com/nlohmann/json/issues/1374)
|
||||
- Serializing/Deserializing a Class containing a vector of itself [\#1373](https://github.com/nlohmann/json/issues/1373)
|
||||
- Retrieving array elements. [\#1369](https://github.com/nlohmann/json/issues/1369)
|
||||
- Deserialize [\#1366](https://github.com/nlohmann/json/issues/1366)
|
||||
- call of overloaded for push\_back and operator+= is ambiguous [\#1352](https://github.com/nlohmann/json/issues/1352)
|
||||
- got an error and cann't figure it out [\#1351](https://github.com/nlohmann/json/issues/1351)
|
||||
- Improve number-to-string conversion [\#1334](https://github.com/nlohmann/json/issues/1334)
|
||||
- Implicit type conversion error on MSVC [\#1333](https://github.com/nlohmann/json/issues/1333)
|
||||
- NuGet Package [\#1132](https://github.com/nlohmann/json/issues/1132)
|
||||
|
||||
- Change macros to numeric\_limits [\#1514](https://github.com/nlohmann/json/pull/1514) ([naszta](https://github.com/naszta))
|
||||
- fix GCC 7.1.1 - 7.2.1 on CentOS [\#1496](https://github.com/nlohmann/json/pull/1496) ([lieff](https://github.com/lieff))
|
||||
- Update Buckaroo instructions in README.md [\#1495](https://github.com/nlohmann/json/pull/1495) ([njlr](https://github.com/njlr))
|
||||
- Fix gcc9 build error test/src/unit-allocator.cpp \(Issue \#1472\) [\#1492](https://github.com/nlohmann/json/pull/1492) ([stac47](https://github.com/stac47))
|
||||
- Fix typo in README.md [\#1491](https://github.com/nlohmann/json/pull/1491) ([nickaein](https://github.com/nickaein))
|
||||
- Do proper endian conversions [\#1489](https://github.com/nlohmann/json/pull/1489) ([andreas-schwab](https://github.com/andreas-schwab))
|
||||
- Fix documentation [\#1477](https://github.com/nlohmann/json/pull/1477) ([nickaein](https://github.com/nickaein))
|
||||
- Implement contains\(\) member function [\#1474](https://github.com/nlohmann/json/pull/1474) ([nickaein](https://github.com/nickaein))
|
||||
- Add operator/= and operator/ to construct a JSON pointer by appending two JSON pointers [\#1469](https://github.com/nlohmann/json/pull/1469) ([garethsb-sony](https://github.com/garethsb-sony))
|
||||
- Disable Clang -Wmismatched-tags warning on tuple\_size / tuple\_element [\#1468](https://github.com/nlohmann/json/pull/1468) ([past-due](https://github.com/past-due))
|
||||
- Disable installation when used as meson subproject. \#1463 [\#1464](https://github.com/nlohmann/json/pull/1464) ([elvisoric](https://github.com/elvisoric))
|
||||
- docs: README typo [\#1455](https://github.com/nlohmann/json/pull/1455) ([wythe](https://github.com/wythe))
|
||||
- remove extra semicolon from readme [\#1451](https://github.com/nlohmann/json/pull/1451) ([Afforix](https://github.com/Afforix))
|
||||
- attempt to fix \#1445, flush buffer in serializer::dump\_escaped in UTF8\_REJECT case. [\#1446](https://github.com/nlohmann/json/pull/1446) ([scinart](https://github.com/scinart))
|
||||
- Use C++11 features supported by CMake 3.1. [\#1441](https://github.com/nlohmann/json/pull/1441) ([iwanders](https://github.com/iwanders))
|
||||
- :rotating\_light: fixed unused variable warning [\#1435](https://github.com/nlohmann/json/pull/1435) ([pboettch](https://github.com/pboettch))
|
||||
- allow push\_back\(\) and pop\_back\(\) calls on json\_pointer [\#1434](https://github.com/nlohmann/json/pull/1434) ([pboettch](https://github.com/pboettch))
|
||||
- Add instructions about using nlohmann/json with the conda package manager [\#1430](https://github.com/nlohmann/json/pull/1430) ([nicoddemus](https://github.com/nicoddemus))
|
||||
- Updated year in README.md [\#1425](https://github.com/nlohmann/json/pull/1425) ([hijxf](https://github.com/hijxf))
|
||||
- Fixed broken links in the README file [\#1423](https://github.com/nlohmann/json/pull/1423) ([skypjack](https://github.com/skypjack))
|
||||
- Fixed broken links in the README file [\#1420](https://github.com/nlohmann/json/pull/1420) ([skypjack](https://github.com/skypjack))
|
||||
- docs: typo in README [\#1417](https://github.com/nlohmann/json/pull/1417) ([wythe](https://github.com/wythe))
|
||||
- Fix x64 target platform for appveyor [\#1414](https://github.com/nlohmann/json/pull/1414) ([nickaein](https://github.com/nickaein))
|
||||
- Improve dump\_integer performance [\#1411](https://github.com/nlohmann/json/pull/1411) ([nickaein](https://github.com/nickaein))
|
||||
- buildsystem: relax requirement on cmake version [\#1409](https://github.com/nlohmann/json/pull/1409) ([yann-morin-1998](https://github.com/yann-morin-1998))
|
||||
- CMake: Optional Install if Embedded [\#1330](https://github.com/nlohmann/json/pull/1330) ([ax3l](https://github.com/ax3l))
|
||||
|
||||
## [v3.5.0](https://github.com/nlohmann/json/releases/tag/v3.5.0) (2018-12-21)
|
||||
[Full Changelog](https://github.com/nlohmann/json/compare/v3.4.0...v3.5.0)
|
||||
|
||||
- Copyconstructor inserts original into array with single element [\#1397](https://github.com/nlohmann/json/issues/1397)
|
||||
- Get value without explicit typecasting [\#1395](https://github.com/nlohmann/json/issues/1395)
|
||||
- Big file parsing [\#1393](https://github.com/nlohmann/json/issues/1393)
|
||||
- some static analysis warning at line 11317 [\#1390](https://github.com/nlohmann/json/issues/1390)
|
||||
- Adding Structured Binding Support [\#1388](https://github.com/nlohmann/json/issues/1388)
|
||||
- map\<json::value\_t, string\> exhibits unexpected behavior [\#1387](https://github.com/nlohmann/json/issues/1387)
|
||||
- Error Code Return [\#1386](https://github.com/nlohmann/json/issues/1386)
|
||||
- using unordered\_map as object type [\#1385](https://github.com/nlohmann/json/issues/1385)
|
||||
- float precision [\#1384](https://github.com/nlohmann/json/issues/1384)
|
||||
- \[json.exception.type\_error.316\] invalid UTF-8 byte at index 1: 0xC3 [\#1383](https://github.com/nlohmann/json/issues/1383)
|
||||
- Inconsistent Constructor \(GCC vs. Clang\) [\#1381](https://github.com/nlohmann/json/issues/1381)
|
||||
- \#define or || [\#1379](https://github.com/nlohmann/json/issues/1379)
|
||||
- How to iterate inside the values ? [\#1377](https://github.com/nlohmann/json/issues/1377)
|
||||
- items\(\) unable to get the elements [\#1375](https://github.com/nlohmann/json/issues/1375)
|
||||
- conversion json to std::map doesn't work for types \<int, double\> [\#1372](https://github.com/nlohmann/json/issues/1372)
|
||||
- A minor issue in the build instructions [\#1371](https://github.com/nlohmann/json/issues/1371)
|
||||
- Using this library without stream ? [\#1370](https://github.com/nlohmann/json/issues/1370)
|
||||
- Writing and reading BSON data [\#1368](https://github.com/nlohmann/json/issues/1368)
|
||||
- Retrieving array elements from object type iterator. [\#1367](https://github.com/nlohmann/json/issues/1367)
|
||||
- json::dump\(\) silently crashes if items contain accented letters [\#1365](https://github.com/nlohmann/json/issues/1365)
|
||||
- warnings in MSVC \(2015\) in 3.4.0 related to bool... [\#1364](https://github.com/nlohmann/json/issues/1364)
|
||||
- Cant compile with -C++17 and beyond compiler options [\#1362](https://github.com/nlohmann/json/issues/1362)
|
||||
- json to concrete type conversion through reference or pointer fails [\#1361](https://github.com/nlohmann/json/issues/1361)
|
||||
- the first attributes of JSON string is misplaced [\#1360](https://github.com/nlohmann/json/issues/1360)
|
||||
- Copy-construct using initializer-list converts objects to arrays [\#1359](https://github.com/nlohmann/json/issues/1359)
|
||||
- About value\(key, default\_value\) and operator\[\]\(key\) [\#1358](https://github.com/nlohmann/json/issues/1358)
|
||||
- Problem with printing json response object [\#1356](https://github.com/nlohmann/json/issues/1356)
|
||||
- Serializing pointer segfaults [\#1355](https://github.com/nlohmann/json/issues/1355)
|
||||
- Read `long long int` data as a number. [\#1354](https://github.com/nlohmann/json/issues/1354)
|
||||
- eclipse oxygen in ubuntu get\<size\_t\> is ambiguous [\#1353](https://github.com/nlohmann/json/issues/1353)
|
||||
- Can't build on Visual Studio 2017 v15.8.9 [\#1350](https://github.com/nlohmann/json/issues/1350)
|
||||
- cannot parse from string? [\#1349](https://github.com/nlohmann/json/issues/1349)
|
||||
- Error: out\_of\_range [\#1348](https://github.com/nlohmann/json/issues/1348)
|
||||
- expansion pattern 'CompatibleObjectType' contains no argument packs, with CUDA 10 [\#1347](https://github.com/nlohmann/json/issues/1347)
|
||||
- Unable to update a value for a nested\(multi-level\) json file [\#1344](https://github.com/nlohmann/json/issues/1344)
|
||||
- Fails to compile when std::iterator\_traits is not SFINAE friendly. [\#1341](https://github.com/nlohmann/json/issues/1341)
|
||||
- EOF flag not set on exhausted input streams. [\#1340](https://github.com/nlohmann/json/issues/1340)
|
||||
- Shadowed Member in merge\_patch [\#1339](https://github.com/nlohmann/json/issues/1339)
|
||||
- Periods/literal dots in keys? [\#1338](https://github.com/nlohmann/json/issues/1338)
|
||||
- Protect macro expansion of commonly defined macros [\#1337](https://github.com/nlohmann/json/issues/1337)
|
||||
- How to validate an input before parsing? [\#1336](https://github.com/nlohmann/json/issues/1336)
|
||||
- Non-verifying dump\(\) alternative for debugging/logging needed [\#1335](https://github.com/nlohmann/json/issues/1335)
|
||||
- Json Libarary is not responding for me in c++ [\#1332](https://github.com/nlohmann/json/issues/1332)
|
||||
- Question - how to find an object in an array [\#1331](https://github.com/nlohmann/json/issues/1331)
|
||||
- Nesting additional data in json object [\#1328](https://github.com/nlohmann/json/issues/1328)
|
||||
- can to\_json\(\) be defined inside a class? [\#1324](https://github.com/nlohmann/json/issues/1324)
|
||||
- CodeBlocks IDE can't find `json.hpp` header [\#1318](https://github.com/nlohmann/json/issues/1318)
|
||||
- Change json\_pointer to provide an iterator begin/end/etc, don't use vectors, and also enable string\_view [\#1312](https://github.com/nlohmann/json/issues/1312)
|
||||
- Xcode - adding it to library [\#1300](https://github.com/nlohmann/json/issues/1300)
|
||||
- unicode: accept char16\_t, char32\_t sequences [\#1298](https://github.com/nlohmann/json/issues/1298)
|
||||
- unicode: char16\_t\* is compiler error, but char16\_t\[\] is accepted [\#1297](https://github.com/nlohmann/json/issues/1297)
|
||||
- Dockerfile Project Help Needed [\#1296](https://github.com/nlohmann/json/issues/1296)
|
||||
- Comparisons between large unsigned and negative signed integers [\#1295](https://github.com/nlohmann/json/issues/1295)
|
||||
- CMake alias to `nlohmann::json` [\#1291](https://github.com/nlohmann/json/issues/1291)
|
||||
- Release zips without tests [\#1285](https://github.com/nlohmann/json/issues/1285)
|
||||
- Suggestion to improve value\(\) accessors with respect to move semantics [\#1275](https://github.com/nlohmann/json/issues/1275)
|
||||
- separate object\_t::key\_type from basic\_json::key\_type, and use an allocator which returns object\_t::key\_type [\#1274](https://github.com/nlohmann/json/issues/1274)
|
||||
- Is there a nice way to associate external values with json elements? [\#1256](https://github.com/nlohmann/json/issues/1256)
|
||||
- Delete by json\_pointer [\#1248](https://github.com/nlohmann/json/issues/1248)
|
||||
- Expose lexer, as a StAX parser [\#1219](https://github.com/nlohmann/json/issues/1219)
|
||||
- Subclassing json\(\) & error on recursive load [\#1201](https://github.com/nlohmann/json/issues/1201)
|
||||
- Check value for existence by json\_pointer [\#1194](https://github.com/nlohmann/json/issues/1194)
|
||||
|
||||
- Feature/add file input adapter [\#1392](https://github.com/nlohmann/json/pull/1392) ([dumarjo](https://github.com/dumarjo))
|
||||
- Added Support for Structured Bindings [\#1391](https://github.com/nlohmann/json/pull/1391) ([pratikpc](https://github.com/pratikpc))
|
||||
- Link to issue \#958 broken [\#1382](https://github.com/nlohmann/json/pull/1382) ([kjpus](https://github.com/kjpus))
|
||||
- readme: fix typo [\#1380](https://github.com/nlohmann/json/pull/1380) ([manu-chroma](https://github.com/manu-chroma))
|
||||
- recommend using explicit from JSON conversions [\#1363](https://github.com/nlohmann/json/pull/1363) ([theodelrieu](https://github.com/theodelrieu))
|
||||
- Fix merge\_patch shadow warning [\#1346](https://github.com/nlohmann/json/pull/1346) ([ax3l](https://github.com/ax3l))
|
||||
- Allow installation via Meson [\#1345](https://github.com/nlohmann/json/pull/1345) ([mpoquet](https://github.com/mpoquet))
|
||||
- Set eofbit on exhausted input stream. [\#1343](https://github.com/nlohmann/json/pull/1343) ([mefyl](https://github.com/mefyl))
|
||||
- Add a SFINAE friendly iterator\_traits and use that instead. [\#1342](https://github.com/nlohmann/json/pull/1342) ([dgavedissian](https://github.com/dgavedissian))
|
||||
- Fix EOL Whitespaces & CMake Spelling [\#1329](https://github.com/nlohmann/json/pull/1329) ([ax3l](https://github.com/ax3l))
|
||||
|
||||
## [v3.4.0](https://github.com/nlohmann/json/releases/tag/v3.4.0) (2018-10-30)
|
||||
[Full Changelog](https://github.com/nlohmann/json/compare/v3.3.0...v3.4.0)
|
||||
|
||||
- Big uint64\_t values are serialized wrong [\#1327](https://github.com/nlohmann/json/issues/1327)
|
||||
- \[Question\] Efficient check for equivalency? [\#1325](https://github.com/nlohmann/json/issues/1325)
|
||||
- Can't use ifstream and .clear\(\) [\#1321](https://github.com/nlohmann/json/issues/1321)
|
||||
- \[Warning\] -Wparentheses on line 555 on single\_include [\#1319](https://github.com/nlohmann/json/issues/1319)
|
||||
- Compilation error using at and find with enum struct [\#1316](https://github.com/nlohmann/json/issues/1316)
|
||||
- Parsing JSON from a web address [\#1311](https://github.com/nlohmann/json/issues/1311)
|
||||
- How to convert JSON to Struct with embeded subject [\#1310](https://github.com/nlohmann/json/issues/1310)
|
||||
- Null safety/coalescing function? [\#1309](https://github.com/nlohmann/json/issues/1309)
|
||||
- Building fails using single include file: json.hpp [\#1308](https://github.com/nlohmann/json/issues/1308)
|
||||
- json::parse\(std::string\) Exception inside packaged Lib [\#1306](https://github.com/nlohmann/json/issues/1306)
|
||||
- Problem in Dockerfile with installation of library [\#1304](https://github.com/nlohmann/json/issues/1304)
|
||||
- compile error in from\_json converting to container with std::pair [\#1299](https://github.com/nlohmann/json/issues/1299)
|
||||
- Json that I am trying to parse, and I am lost Structure Array below top level [\#1293](https://github.com/nlohmann/json/issues/1293)
|
||||
- Serializing std::variant causes stack overflow [\#1292](https://github.com/nlohmann/json/issues/1292)
|
||||
- How do I go about customising from\_json to support \_\_int128\_t/\_\_uint128\_t? [\#1290](https://github.com/nlohmann/json/issues/1290)
|
||||
- merge\_patch: inconsistent behaviour merging empty sub-object [\#1289](https://github.com/nlohmann/json/issues/1289)
|
||||
- Buffer over/underrun using UBJson? [\#1288](https://github.com/nlohmann/json/issues/1288)
|
||||
- Enable the latest C++ standard with Visual Studio [\#1287](https://github.com/nlohmann/json/issues/1287)
|
||||
- truncation of constant value in to\_cbor\(\) [\#1286](https://github.com/nlohmann/json/issues/1286)
|
||||
- eosio.wasmsdk error [\#1284](https://github.com/nlohmann/json/issues/1284)
|
||||
- use the same interface for writing arrays and non-arrays [\#1283](https://github.com/nlohmann/json/issues/1283)
|
||||
- How to read json file with optional entries and entries with different types [\#1281](https://github.com/nlohmann/json/issues/1281)
|
||||
- merge result not as espected [\#1279](https://github.com/nlohmann/json/issues/1279)
|
||||
- how to get only "name" from below json [\#1278](https://github.com/nlohmann/json/issues/1278)
|
||||
- syntax error on right json string [\#1276](https://github.com/nlohmann/json/issues/1276)
|
||||
- Parsing JSON Array where members have no key, using custom types [\#1267](https://github.com/nlohmann/json/issues/1267)
|
||||
- I get a json exception periodically from json::parse for the same json [\#1263](https://github.com/nlohmann/json/issues/1263)
|
||||
- serialize std::variant\<...\> [\#1261](https://github.com/nlohmann/json/issues/1261)
|
||||
- GCC 8.2.1. Compilation error: invalid conversion from... [\#1246](https://github.com/nlohmann/json/issues/1246)
|
||||
- BSON support [\#1244](https://github.com/nlohmann/json/issues/1244)
|
||||
- enum to json mapping [\#1208](https://github.com/nlohmann/json/issues/1208)
|
||||
- Soften the landing when dumping non-UTF8 strings \(type\_error.316 exception\) [\#1198](https://github.com/nlohmann/json/issues/1198)
|
||||
- CMakeLists.txt in release zips? [\#1184](https://github.com/nlohmann/json/issues/1184)
|
||||
|
||||
- Add macro to define enum/JSON mapping [\#1323](https://github.com/nlohmann/json/pull/1323) ([nlohmann](https://github.com/nlohmann))
|
||||
- Add BSON support [\#1320](https://github.com/nlohmann/json/pull/1320) ([nlohmann](https://github.com/nlohmann))
|
||||
- Properly convert constants to CharType [\#1315](https://github.com/nlohmann/json/pull/1315) ([nlohmann](https://github.com/nlohmann))
|
||||
- Allow to set error handler for decoding errors [\#1314](https://github.com/nlohmann/json/pull/1314) ([nlohmann](https://github.com/nlohmann))
|
||||
- Add Meson related info to README [\#1305](https://github.com/nlohmann/json/pull/1305) ([koponomarenko](https://github.com/koponomarenko))
|
||||
- Improve diagnostic messages for binary formats [\#1303](https://github.com/nlohmann/json/pull/1303) ([nlohmann](https://github.com/nlohmann))
|
||||
- add new is\_constructible\_\* traits used in from\_json [\#1301](https://github.com/nlohmann/json/pull/1301) ([theodelrieu](https://github.com/theodelrieu))
|
||||
- add constraints for variadic json\_ref constructors [\#1294](https://github.com/nlohmann/json/pull/1294) ([theodelrieu](https://github.com/theodelrieu))
|
||||
- Improve diagnostic messages [\#1282](https://github.com/nlohmann/json/pull/1282) ([nlohmann](https://github.com/nlohmann))
|
||||
- Removed linter warnings [\#1280](https://github.com/nlohmann/json/pull/1280) ([nlohmann](https://github.com/nlohmann))
|
||||
- Thirdparty benchmark: Fix Clang detection. [\#1277](https://github.com/nlohmann/json/pull/1277) ([Lord-Kamina](https://github.com/Lord-Kamina))
|
||||
|
||||
## [v3.3.0](https://github.com/nlohmann/json/releases/tag/v3.3.0) (2018-10-05)
|
||||
[Full Changelog](https://github.com/nlohmann/json/compare/v3.2.0...v3.3.0)
|
||||
|
||||
- When key is not found print the key name into error too [\#1273](https://github.com/nlohmann/json/issues/1273)
|
||||
- Visual Studio 2017 15.8.5 "conditional expression is constant" warning on Line 1851 in json.hpp [\#1268](https://github.com/nlohmann/json/issues/1268)
|
||||
- how can we get this working on WSL? [\#1264](https://github.com/nlohmann/json/issues/1264)
|
||||
- Help needed [\#1259](https://github.com/nlohmann/json/issues/1259)
|
||||
- A way to get to a JSON values "key" [\#1258](https://github.com/nlohmann/json/issues/1258)
|
||||
- While compiling got 76 errors [\#1255](https://github.com/nlohmann/json/issues/1255)
|
||||
- Two blackslashes on json output file [\#1253](https://github.com/nlohmann/json/issues/1253)
|
||||
- Including nlohmann the badwrong way. [\#1250](https://github.com/nlohmann/json/issues/1250)
|
||||
- how to build with clang? [\#1247](https://github.com/nlohmann/json/issues/1247)
|
||||
- Cmake target\_link\_libraries unable to find nlohmann\_json since version 3.2.0 [\#1243](https://github.com/nlohmann/json/issues/1243)
|
||||
- \[Question\] Access to end\(\) iterator reference [\#1242](https://github.com/nlohmann/json/issues/1242)
|
||||
- Parsing different json format [\#1241](https://github.com/nlohmann/json/issues/1241)
|
||||
- Parsing Multiple JSON Files [\#1240](https://github.com/nlohmann/json/issues/1240)
|
||||
- Doesn't compile under C++17 [\#1239](https://github.com/nlohmann/json/issues/1239)
|
||||
- Conversion operator for nlohmann::json is not SFINAE friendly [\#1237](https://github.com/nlohmann/json/issues/1237)
|
||||
- Custom deserialization of number\_float\_t [\#1236](https://github.com/nlohmann/json/issues/1236)
|
||||
- Move tests to a separate repo [\#1235](https://github.com/nlohmann/json/issues/1235)
|
||||
- deprecated-declarations warnings when compiling tests with GCC 8.2.1. [\#1233](https://github.com/nlohmann/json/issues/1233)
|
||||
- Incomplete type with json\_fwd.hpp [\#1232](https://github.com/nlohmann/json/issues/1232)
|
||||
- Parse Error [\#1229](https://github.com/nlohmann/json/issues/1229)
|
||||
- json::get function with argument [\#1227](https://github.com/nlohmann/json/issues/1227)
|
||||
- questions regarding from\_json [\#1226](https://github.com/nlohmann/json/issues/1226)
|
||||
- Lambda in unevaluated context [\#1225](https://github.com/nlohmann/json/issues/1225)
|
||||
- NLohmann doesn't compile when enabling strict warning policies [\#1224](https://github.com/nlohmann/json/issues/1224)
|
||||
- Creating array of objects [\#1223](https://github.com/nlohmann/json/issues/1223)
|
||||
- Somewhat unhelpful error message "cannot use operator\[\] with object" [\#1220](https://github.com/nlohmann/json/issues/1220)
|
||||
- single\_include json.hpp [\#1218](https://github.com/nlohmann/json/issues/1218)
|
||||
- Maps with enum class keys which are convertible to JSON strings should be converted to JSON dictionaries [\#1217](https://github.com/nlohmann/json/issues/1217)
|
||||
- Adding JSON Array to the Array [\#1216](https://github.com/nlohmann/json/issues/1216)
|
||||
- Best way to output a vector of a given type to json [\#1215](https://github.com/nlohmann/json/issues/1215)
|
||||
- compiler warning: double definition of macro JSON\_INTERNAL\_CATCH [\#1213](https://github.com/nlohmann/json/issues/1213)
|
||||
- Compilation error when using MOCK\_METHOD1 from GMock and nlohmann::json [\#1212](https://github.com/nlohmann/json/issues/1212)
|
||||
- Issues parsing a previously encoded binary \(non-UTF8\) string. [\#1211](https://github.com/nlohmann/json/issues/1211)
|
||||
- Yet another ordering question: char \* and parse\(\) [\#1209](https://github.com/nlohmann/json/issues/1209)
|
||||
- Error using gcc 8.1.0 on Ubuntu 14.04 [\#1207](https://github.com/nlohmann/json/issues/1207)
|
||||
- "type must be string, but is " std::string\(j.type\_name\(\) [\#1206](https://github.com/nlohmann/json/issues/1206)
|
||||
- Returning empty json object from a function of type const json& ? [\#1205](https://github.com/nlohmann/json/issues/1205)
|
||||
- VS2017 compiler suggests using constexpr if [\#1204](https://github.com/nlohmann/json/issues/1204)
|
||||
- Template instatiation error on compiling [\#1203](https://github.com/nlohmann/json/issues/1203)
|
||||
- BUG - json dump field with unicode -\> array of ints \(instead of string\) [\#1197](https://github.com/nlohmann/json/issues/1197)
|
||||
- Compile error using Code::Blocks // mingw-w64 GCC 8.1.0 - "Incomplete Type" [\#1193](https://github.com/nlohmann/json/issues/1193)
|
||||
- SEGFAULT on arm target [\#1190](https://github.com/nlohmann/json/issues/1190)
|
||||
- Compiler crash with old Clang [\#1179](https://github.com/nlohmann/json/issues/1179)
|
||||
- Custom Precision on floating point numbers [\#1170](https://github.com/nlohmann/json/issues/1170)
|
||||
- Can we have a json\_view class like std::string\_view? [\#1158](https://github.com/nlohmann/json/issues/1158)
|
||||
- improve error handling [\#1152](https://github.com/nlohmann/json/issues/1152)
|
||||
- We should remove static\_asserts [\#960](https://github.com/nlohmann/json/issues/960)
|
||||
|
||||
- Fix warning C4127: conditional expression is constant [\#1272](https://github.com/nlohmann/json/pull/1272) ([antonioborondo](https://github.com/antonioborondo))
|
||||
- Turn off additional deprecation warnings for GCC. [\#1271](https://github.com/nlohmann/json/pull/1271) ([chuckatkins](https://github.com/chuckatkins))
|
||||
- docs: Add additional CMake documentation [\#1270](https://github.com/nlohmann/json/pull/1270) ([chuckatkins](https://github.com/chuckatkins))
|
||||
- unit-testsuites.cpp: fix hangup if file not found [\#1262](https://github.com/nlohmann/json/pull/1262) ([knilch0r](https://github.com/knilch0r))
|
||||
- Fix broken cmake imported target alias [\#1260](https://github.com/nlohmann/json/pull/1260) ([chuckatkins](https://github.com/chuckatkins))
|
||||
- GCC 48 [\#1257](https://github.com/nlohmann/json/pull/1257) ([henryiii](https://github.com/henryiii))
|
||||
- Add version and license to meson.build [\#1252](https://github.com/nlohmann/json/pull/1252) ([koponomarenko](https://github.com/koponomarenko))
|
||||
- \#1179 Reordered the code. It seems to stop clang 3.4.2 in RHEL 7 from crash… [\#1249](https://github.com/nlohmann/json/pull/1249) ([LEgregius](https://github.com/LEgregius))
|
||||
- Use a version check to provide backwards comatible CMake imported target names [\#1245](https://github.com/nlohmann/json/pull/1245) ([chuckatkins](https://github.com/chuckatkins))
|
||||
- Fix issue \#1237 [\#1238](https://github.com/nlohmann/json/pull/1238) ([theodelrieu](https://github.com/theodelrieu))
|
||||
- Add a get overload taking a parameter. [\#1231](https://github.com/nlohmann/json/pull/1231) ([theodelrieu](https://github.com/theodelrieu))
|
||||
- Move lambda out of unevaluated context [\#1230](https://github.com/nlohmann/json/pull/1230) ([mandreyel](https://github.com/mandreyel))
|
||||
- Remove static asserts [\#1228](https://github.com/nlohmann/json/pull/1228) ([theodelrieu](https://github.com/theodelrieu))
|
||||
- Better error 305 [\#1221](https://github.com/nlohmann/json/pull/1221) ([rivertam](https://github.com/rivertam))
|
||||
- Fix \#1213 [\#1214](https://github.com/nlohmann/json/pull/1214) ([simnalamburt](https://github.com/simnalamburt))
|
||||
- Export package to allow builds without installing [\#1202](https://github.com/nlohmann/json/pull/1202) ([dennisfischer](https://github.com/dennisfischer))
|
||||
|
||||
## [v3.2.0](https://github.com/nlohmann/json/releases/tag/v3.2.0) (2018-08-20)
|
||||
[Full Changelog](https://github.com/nlohmann/json/compare/v3.1.2...v3.2.0)
|
||||
|
||||
- Am I doing this wrong? Getting an empty string [\#1199](https://github.com/nlohmann/json/issues/1199)
|
||||
- Incompatible Pointer Type [\#1196](https://github.com/nlohmann/json/issues/1196)
|
||||
- json.exception.type\_error.316 [\#1195](https://github.com/nlohmann/json/issues/1195)
|
||||
- Strange warnings in Code::Blocks 17.12, GNU GCC [\#1192](https://github.com/nlohmann/json/issues/1192)
|
||||
- \[Question\] Current place in code to change floating point resolution [\#1191](https://github.com/nlohmann/json/issues/1191)
|
||||
- Add key name when throwing type error [\#1189](https://github.com/nlohmann/json/issues/1189)
|
||||
- Not able to include in visual studio code? [\#1188](https://github.com/nlohmann/json/issues/1188)
|
||||
- Get an Index or row number of an element [\#1186](https://github.com/nlohmann/json/issues/1186)
|
||||
- reduce repos size [\#1185](https://github.com/nlohmann/json/issues/1185)
|
||||
- Difference between `merge\_patch` and `update` [\#1183](https://github.com/nlohmann/json/issues/1183)
|
||||
- Is there a way to get an element from a JSON without throwing an exception on failure? [\#1182](https://github.com/nlohmann/json/issues/1182)
|
||||
- to\_string? [\#1181](https://github.com/nlohmann/json/issues/1181)
|
||||
- How to cache a json object's pointer into a map? [\#1180](https://github.com/nlohmann/json/issues/1180)
|
||||
- Can this library work within a Qt project for Android using Qt Creator? [\#1178](https://github.com/nlohmann/json/issues/1178)
|
||||
- How to get all keys of one object? [\#1177](https://github.com/nlohmann/json/issues/1177)
|
||||
- How can I only parse the first level and get the value as string? [\#1175](https://github.com/nlohmann/json/issues/1175)
|
||||
- I have a query regarding nlohmann::basic\_json::basic\_json [\#1174](https://github.com/nlohmann/json/issues/1174)
|
||||
- unordered\_map with vectors won't convert to json? [\#1173](https://github.com/nlohmann/json/issues/1173)
|
||||
- return json objects from functions [\#1172](https://github.com/nlohmann/json/issues/1172)
|
||||
- Problem when exporting to CBOR [\#1171](https://github.com/nlohmann/json/issues/1171)
|
||||
- Roundtripping null to nullptr does not work [\#1169](https://github.com/nlohmann/json/issues/1169)
|
||||
- MSVC fails to compile std::swap specialization for nlohmann::json [\#1168](https://github.com/nlohmann/json/issues/1168)
|
||||
- Unexpected behaviour of is\_null - Part II [\#1167](https://github.com/nlohmann/json/issues/1167)
|
||||
- Floating point imprecision [\#1166](https://github.com/nlohmann/json/issues/1166)
|
||||
- Combine json objects into one? [\#1165](https://github.com/nlohmann/json/issues/1165)
|
||||
- Is there any way to know if the object has changed? [\#1164](https://github.com/nlohmann/json/issues/1164)
|
||||
- Value throws on null string [\#1163](https://github.com/nlohmann/json/issues/1163)
|
||||
- Weird template issue in large project [\#1162](https://github.com/nlohmann/json/issues/1162)
|
||||
- \_json returns a different result vs ::parse [\#1161](https://github.com/nlohmann/json/issues/1161)
|
||||
- Showing difference between two json objects [\#1160](https://github.com/nlohmann/json/issues/1160)
|
||||
- no instance of overloaded function "std::swap" matches the specified type [\#1159](https://github.com/nlohmann/json/issues/1159)
|
||||
- resize\(...\)? [\#1157](https://github.com/nlohmann/json/issues/1157)
|
||||
- Issue with struct nested in class' to\_json [\#1155](https://github.com/nlohmann/json/issues/1155)
|
||||
- Deserialize std::map with std::nan [\#1154](https://github.com/nlohmann/json/issues/1154)
|
||||
- Parse throwing errors [\#1149](https://github.com/nlohmann/json/issues/1149)
|
||||
- cocoapod integration [\#1148](https://github.com/nlohmann/json/issues/1148)
|
||||
- wstring parsing [\#1147](https://github.com/nlohmann/json/issues/1147)
|
||||
- Is it possible to dump a two-dimensional array to "\[\[null\],\[1,2,3\]\]"? [\#1146](https://github.com/nlohmann/json/issues/1146)
|
||||
- Want to write a class member variable and a struct variable \( this structure is inside the class\) to the json file [\#1145](https://github.com/nlohmann/json/issues/1145)
|
||||
- Does json support converting an instance of a struct into json string? [\#1143](https://github.com/nlohmann/json/issues/1143)
|
||||
- \#Most efficient way to search for child parameters \(recursive find?\) [\#1141](https://github.com/nlohmann/json/issues/1141)
|
||||
- could not find to\_json\(\) method in T's namespace [\#1140](https://github.com/nlohmann/json/issues/1140)
|
||||
- chars get treated as JSON numbers not JSON strings [\#1139](https://github.com/nlohmann/json/issues/1139)
|
||||
- How do I count number of objects in array? [\#1137](https://github.com/nlohmann/json/issues/1137)
|
||||
- Serializing a vector of classes? [\#1136](https://github.com/nlohmann/json/issues/1136)
|
||||
- Compile error. Unable convert form nullptr to nullptr&& [\#1135](https://github.com/nlohmann/json/issues/1135)
|
||||
- std::unordered\_map in struct, serialization [\#1133](https://github.com/nlohmann/json/issues/1133)
|
||||
- dump\(\) can't handle umlauts [\#1131](https://github.com/nlohmann/json/issues/1131)
|
||||
- Add a way to get a key reference from the iterator [\#1127](https://github.com/nlohmann/json/issues/1127)
|
||||
- can't not parse "\\“ string [\#1123](https://github.com/nlohmann/json/issues/1123)
|
||||
- if json file contain Internationalization chars , get exception [\#1122](https://github.com/nlohmann/json/issues/1122)
|
||||
- How to use a json::iterator dereferenced value in code? [\#1120](https://github.com/nlohmann/json/issues/1120)
|
||||
- clang compiler: error : unknown type name 'not' [\#1119](https://github.com/nlohmann/json/issues/1119)
|
||||
- Disable implicit conversions from json to std::initializer\_list\<T\> for any T [\#1118](https://github.com/nlohmann/json/issues/1118)
|
||||
- Implicit conversions to complex types can lead to surprising and confusing errors [\#1116](https://github.com/nlohmann/json/issues/1116)
|
||||
- How can I write from\_json for a complex datatype that is not default constructible? [\#1115](https://github.com/nlohmann/json/issues/1115)
|
||||
- Compile error in VS2015 when compiling unit-conversions.cpp [\#1114](https://github.com/nlohmann/json/issues/1114)
|
||||
- ADL Serializer for std::any / boost::any [\#1113](https://github.com/nlohmann/json/issues/1113)
|
||||
- Unexpected behaviour of is\_null [\#1112](https://github.com/nlohmann/json/issues/1112)
|
||||
- How to resolve " undefined reference to `std::\_\_throw\_bad\_cast\(\)'" [\#1111](https://github.com/nlohmann/json/issues/1111)
|
||||
- cannot compile on ubuntu 18.04 and 16.04 [\#1110](https://github.com/nlohmann/json/issues/1110)
|
||||
- JSON representation for floating point values has too many digits [\#1109](https://github.com/nlohmann/json/issues/1109)
|
||||
- Not working for classes containing "\_declspec\(dllimport\)" in their declaration [\#1108](https://github.com/nlohmann/json/issues/1108)
|
||||
- Get keys from json object [\#1107](https://github.com/nlohmann/json/issues/1107)
|
||||
- dump\(\) without alphabetical order [\#1106](https://github.com/nlohmann/json/issues/1106)
|
||||
- Cannot deserialize types using std::ratio [\#1105](https://github.com/nlohmann/json/issues/1105)
|
||||
- i want to learn json [\#1104](https://github.com/nlohmann/json/issues/1104)
|
||||
- Type checking during compile [\#1103](https://github.com/nlohmann/json/issues/1103)
|
||||
- Iterate through sub items [\#1102](https://github.com/nlohmann/json/issues/1102)
|
||||
- cppcheck failing for version 3.1.2 [\#1101](https://github.com/nlohmann/json/issues/1101)
|
||||
- Deserializing std::map [\#1100](https://github.com/nlohmann/json/issues/1100)
|
||||
- accessing key by reference [\#1098](https://github.com/nlohmann/json/issues/1098)
|
||||
- clang 3.8.0 croaks while trying to compile with debug symbols [\#1097](https://github.com/nlohmann/json/issues/1097)
|
||||
- Serialize a list of class objects with json [\#1096](https://github.com/nlohmann/json/issues/1096)
|
||||
- Small question [\#1094](https://github.com/nlohmann/json/issues/1094)
|
||||
- Upgrading to 3.x: to\_/from\_json with enum class [\#1093](https://github.com/nlohmann/json/issues/1093)
|
||||
- Q: few questions about json construction [\#1092](https://github.com/nlohmann/json/issues/1092)
|
||||
- general crayCC compilation failure [\#1091](https://github.com/nlohmann/json/issues/1091)
|
||||
- Merge Patch clears original data [\#1090](https://github.com/nlohmann/json/issues/1090)
|
||||
- \[Question\] how to use nlohmann/json in c++? [\#1088](https://github.com/nlohmann/json/issues/1088)
|
||||
- C++17 decomposition declaration support [\#1087](https://github.com/nlohmann/json/issues/1087)
|
||||
- \[Question\] Access multi-level json objects [\#1086](https://github.com/nlohmann/json/issues/1086)
|
||||
- Serializing vector [\#1085](https://github.com/nlohmann/json/issues/1085)
|
||||
- update nested value in multi hierarchy json object [\#1084](https://github.com/nlohmann/json/issues/1084)
|
||||
- Overriding default values? [\#1083](https://github.com/nlohmann/json/issues/1083)
|
||||
- detail namespace collision with Cereal? [\#1082](https://github.com/nlohmann/json/issues/1082)
|
||||
- Error using json.dump\(\); [\#1081](https://github.com/nlohmann/json/issues/1081)
|
||||
- Consuming TCP Stream [\#1080](https://github.com/nlohmann/json/issues/1080)
|
||||
- Compilation error with strong typed enums in map in combination with namespaces [\#1079](https://github.com/nlohmann/json/issues/1079)
|
||||
- cassert error [\#1076](https://github.com/nlohmann/json/issues/1076)
|
||||
- Valid json data not being parsed [\#1075](https://github.com/nlohmann/json/issues/1075)
|
||||
- Feature request :: Better testing for key existance without try/catch [\#1074](https://github.com/nlohmann/json/issues/1074)
|
||||
- Hi, I have input like a.b.c and want to convert it to \"a\"{\"b\": \"c\"} form. Any suggestions how do I do this? Thanks. [\#1073](https://github.com/nlohmann/json/issues/1073)
|
||||
- ADL deserializer not picked up for non default-constructible type [\#1072](https://github.com/nlohmann/json/issues/1072)
|
||||
- Deserializing std::array doesn't compiler \(no insert\(\)\) [\#1071](https://github.com/nlohmann/json/issues/1071)
|
||||
- Serializing OpenCV Mat problem [\#1070](https://github.com/nlohmann/json/issues/1070)
|
||||
- Compilation error with ICPC compiler [\#1068](https://github.com/nlohmann/json/issues/1068)
|
||||
- Minimal branch? [\#1066](https://github.com/nlohmann/json/issues/1066)
|
||||
- Not existing value, crash [\#1065](https://github.com/nlohmann/json/issues/1065)
|
||||
- cyryllic symbols [\#1064](https://github.com/nlohmann/json/issues/1064)
|
||||
- newbie usage question [\#1063](https://github.com/nlohmann/json/issues/1063)
|
||||
- Trying j\["strTest"\] = "%A" produces "strTest": "-0X1.CCCCCCCCCCCCCP+205" [\#1062](https://github.com/nlohmann/json/issues/1062)
|
||||
- convert json value to std::string??? [\#1061](https://github.com/nlohmann/json/issues/1061)
|
||||
- Commented out test cases, should they be removed? [\#1060](https://github.com/nlohmann/json/issues/1060)
|
||||
- different behaviour between clang and gcc with braced initialization [\#1059](https://github.com/nlohmann/json/issues/1059)
|
||||
- json array: initialize with prescribed size and `resize` method. [\#1057](https://github.com/nlohmann/json/issues/1057)
|
||||
- Is it possible to use exceptions istead of assertions? [\#1056](https://github.com/nlohmann/json/issues/1056)
|
||||
- when using assign operator in with json object a static assertion fails.. [\#1055](https://github.com/nlohmann/json/issues/1055)
|
||||
- Iterate over leafs of a JSON data structure: enrich the JSON pointer API [\#1054](https://github.com/nlohmann/json/issues/1054)
|
||||
- \[Feature request\] Access by path [\#1053](https://github.com/nlohmann/json/issues/1053)
|
||||
- document that implicit js -\> primitive conversion does not work for std::string::value\_type and why [\#1052](https://github.com/nlohmann/json/issues/1052)
|
||||
- error: ‘BasicJsonType’ in namespace ‘::’ does not name a type [\#1051](https://github.com/nlohmann/json/issues/1051)
|
||||
- Destructor is called when filling object through assignement [\#1050](https://github.com/nlohmann/json/issues/1050)
|
||||
- Is this thing thread safe for reads? [\#1049](https://github.com/nlohmann/json/issues/1049)
|
||||
- clang-tidy: Call to virtual function during construction [\#1046](https://github.com/nlohmann/json/issues/1046)
|
||||
- Using STL algorithms with JSON containers with expected results? [\#1045](https://github.com/nlohmann/json/issues/1045)
|
||||
- Usage with gtest/gmock not working as expected [\#1044](https://github.com/nlohmann/json/issues/1044)
|
||||
- Consequences of from\_json / to\_json being in namespace of data struct. [\#1042](https://github.com/nlohmann/json/issues/1042)
|
||||
- const\_reference operator\[\]\(const typename object\_t::key\_type& key\) const throw instead of assert [\#1039](https://github.com/nlohmann/json/issues/1039)
|
||||
- Trying to retrieve data from nested objects [\#1038](https://github.com/nlohmann/json/issues/1038)
|
||||
- Direct download link for json\_fwd.hpp? [\#1037](https://github.com/nlohmann/json/issues/1037)
|
||||
- I know the library supports UTF-8, but failed to dump the value [\#1036](https://github.com/nlohmann/json/issues/1036)
|
||||
- Putting a Vec3-like vector into a json object [\#1035](https://github.com/nlohmann/json/issues/1035)
|
||||
- Ternary operator crash [\#1034](https://github.com/nlohmann/json/issues/1034)
|
||||
- Issued with Clion Inspection Resolution since 2018.1 [\#1033](https://github.com/nlohmann/json/issues/1033)
|
||||
- Some testcases fail and one never finishes [\#1032](https://github.com/nlohmann/json/issues/1032)
|
||||
- Can this class work with wchar\_t / std::wstring? [\#1031](https://github.com/nlohmann/json/issues/1031)
|
||||
- Makefile: Valgrind flags have no effect [\#1030](https://github.com/nlohmann/json/issues/1030)
|
||||
- 「==」 Should be 「\>」 [\#1029](https://github.com/nlohmann/json/issues/1029)
|
||||
- HOCON reader? [\#1027](https://github.com/nlohmann/json/issues/1027)
|
||||
- add json string in previous string?? [\#1025](https://github.com/nlohmann/json/issues/1025)
|
||||
- RFC: fluent parsing interface [\#1023](https://github.com/nlohmann/json/issues/1023)
|
||||
- Does it support chinese character? [\#1022](https://github.com/nlohmann/json/issues/1022)
|
||||
- to/from\_msgpack only works with standard typization [\#1021](https://github.com/nlohmann/json/issues/1021)
|
||||
- Build failure using latest clang and GCC compilers [\#1020](https://github.com/nlohmann/json/issues/1020)
|
||||
- can two json objects be concatenated? [\#1019](https://github.com/nlohmann/json/issues/1019)
|
||||
- Erase by integer index [\#1018](https://github.com/nlohmann/json/issues/1018)
|
||||
- Function find overload taking a json\_pointer [\#1017](https://github.com/nlohmann/json/issues/1017)
|
||||
- I think should implement an parser function [\#1016](https://github.com/nlohmann/json/issues/1016)
|
||||
- Readme gif [\#1015](https://github.com/nlohmann/json/issues/1015)
|
||||
- Python bindings [\#1014](https://github.com/nlohmann/json/issues/1014)
|
||||
- how to add two json string in single object?? [\#1012](https://github.com/nlohmann/json/issues/1012)
|
||||
- how to serialize class Object \(convert data in object into json\)?? [\#1011](https://github.com/nlohmann/json/issues/1011)
|
||||
- Enable forward declaration of json by making json a class instead of a using declaration [\#997](https://github.com/nlohmann/json/issues/997)
|
||||
- compilation error while using intel c++ compiler 2018 [\#994](https://github.com/nlohmann/json/issues/994)
|
||||
- How to create a json variable? [\#990](https://github.com/nlohmann/json/issues/990)
|
||||
- istream \>\> json --- 1st character skipped in stream [\#976](https://github.com/nlohmann/json/issues/976)
|
||||
- Add a SAX parser [\#971](https://github.com/nlohmann/json/issues/971)
|
||||
- Add Key name to Exception [\#932](https://github.com/nlohmann/json/issues/932)
|
||||
- How to solve large json file? [\#927](https://github.com/nlohmann/json/issues/927)
|
||||
- json\_pointer public push\_back, pop\_back [\#837](https://github.com/nlohmann/json/issues/837)
|
||||
- Using input\_adapter in a slightly unexpected way [\#834](https://github.com/nlohmann/json/issues/834)
|
||||
|
||||
- Fix -Wno-sometimes-uninitialized by initializing "result" in parse\_sax [\#1200](https://github.com/nlohmann/json/pull/1200) ([thyu](https://github.com/thyu))
|
||||
- \[RFC\] Introduce a new macro function: JSON\_INTERNAL\_CATCH [\#1187](https://github.com/nlohmann/json/pull/1187) ([simnalamburt](https://github.com/simnalamburt))
|
||||
- Fix unit tests that were silently skipped or crashed \(depending on the compiler\) [\#1176](https://github.com/nlohmann/json/pull/1176) ([grembo](https://github.com/grembo))
|
||||
- Refactor/no virtual sax [\#1153](https://github.com/nlohmann/json/pull/1153) ([theodelrieu](https://github.com/theodelrieu))
|
||||
- Fixed compiler error in VS 2015 for debug mode [\#1151](https://github.com/nlohmann/json/pull/1151) ([sonulohani](https://github.com/sonulohani))
|
||||
- Fix links to cppreference named requirements \(formerly concepts\) [\#1144](https://github.com/nlohmann/json/pull/1144) ([jrakow](https://github.com/jrakow))
|
||||
- meson: fix include directory [\#1142](https://github.com/nlohmann/json/pull/1142) ([jrakow](https://github.com/jrakow))
|
||||
- Feature/unordered map conversion [\#1138](https://github.com/nlohmann/json/pull/1138) ([theodelrieu](https://github.com/theodelrieu))
|
||||
- fixed compile error for \#1045 [\#1134](https://github.com/nlohmann/json/pull/1134) ([Daniel599](https://github.com/Daniel599))
|
||||
- test \(non\)equality for alt\_string implementation [\#1130](https://github.com/nlohmann/json/pull/1130) ([agrianius](https://github.com/agrianius))
|
||||
- remove stringstream dependency [\#1117](https://github.com/nlohmann/json/pull/1117) ([TinyTinni](https://github.com/TinyTinni))
|
||||
- Provide a from\_json overload for std::map [\#1089](https://github.com/nlohmann/json/pull/1089) ([theodelrieu](https://github.com/theodelrieu))
|
||||
- fix typo in README [\#1078](https://github.com/nlohmann/json/pull/1078) ([martin-mfg](https://github.com/martin-mfg))
|
||||
- Fix typo [\#1058](https://github.com/nlohmann/json/pull/1058) ([dns13](https://github.com/dns13))
|
||||
- Misc cmake packaging enhancements [\#1048](https://github.com/nlohmann/json/pull/1048) ([chuckatkins](https://github.com/chuckatkins))
|
||||
- Fixed incorrect LLVM version number in README [\#1047](https://github.com/nlohmann/json/pull/1047) ([jammehcow](https://github.com/jammehcow))
|
||||
- Fix trivial typo in comment. [\#1043](https://github.com/nlohmann/json/pull/1043) ([coryan](https://github.com/coryan))
|
||||
- Package Manager: Spack [\#1041](https://github.com/nlohmann/json/pull/1041) ([ax3l](https://github.com/ax3l))
|
||||
- CMake: 3.8+ is Sufficient [\#1040](https://github.com/nlohmann/json/pull/1040) ([ax3l](https://github.com/ax3l))
|
||||
- Added support for string\_view in C++17 [\#1028](https://github.com/nlohmann/json/pull/1028) ([gracicot](https://github.com/gracicot))
|
||||
- Added public target\_compile\_features for auto and constexpr [\#1026](https://github.com/nlohmann/json/pull/1026) ([ktonon](https://github.com/ktonon))
|
||||
|
||||
## [v3.1.2](https://github.com/nlohmann/json/releases/tag/v3.1.2) (2018-03-14)
|
||||
[Full Changelog](https://github.com/nlohmann/json/compare/v3.1.1...v3.1.2)
|
||||
|
||||
- STL containers are always serialized to a nested array like \[\[1,2,3\]\] [\#1013](https://github.com/nlohmann/json/issues/1013)
|
||||
- The library doesn't want to insert an unordered\_map [\#1010](https://github.com/nlohmann/json/issues/1010)
|
||||
- Convert Json to uint8\_t [\#1008](https://github.com/nlohmann/json/issues/1008)
|
||||
- How to compare two JSON objects? [\#1007](https://github.com/nlohmann/json/issues/1007)
|
||||
- Syntax checking [\#1003](https://github.com/nlohmann/json/issues/1003)
|
||||
- more than one operator '=' matches these operands [\#1002](https://github.com/nlohmann/json/issues/1002)
|
||||
- How to check if key existed [\#1000](https://github.com/nlohmann/json/issues/1000)
|
||||
- nlohmann::json::parse exhaust memory in go binding [\#999](https://github.com/nlohmann/json/issues/999)
|
||||
- Range-based iteration over a non-array object [\#998](https://github.com/nlohmann/json/issues/998)
|
||||
- get\<T\> for types that are not default constructible [\#996](https://github.com/nlohmann/json/issues/996)
|
||||
- Prevent Null values to appear in .dump\(\) [\#995](https://github.com/nlohmann/json/issues/995)
|
||||
- number parsing [\#993](https://github.com/nlohmann/json/issues/993)
|
||||
- C2664 \(C++/CLR\) cannot convert 'nullptr' to 'nullptr &&' [\#987](https://github.com/nlohmann/json/issues/987)
|
||||
- Uniform initialization from another json object differs between gcc and clang. [\#985](https://github.com/nlohmann/json/issues/985)
|
||||
- Problem with adding the lib as a submodule [\#983](https://github.com/nlohmann/json/issues/983)
|
||||
- UTF-8/Unicode error [\#982](https://github.com/nlohmann/json/issues/982)
|
||||
- "forcing MSVC stacktrace to show which T we're talking about." error [\#980](https://github.com/nlohmann/json/issues/980)
|
||||
- reverse order of serialization [\#979](https://github.com/nlohmann/json/issues/979)
|
||||
- Assigning between different json types [\#977](https://github.com/nlohmann/json/issues/977)
|
||||
- Support serialisation of `unique\_ptr\<\>` and `shared\_ptr\<\>` [\#975](https://github.com/nlohmann/json/issues/975)
|
||||
- Unexpected end of input \(not same as one before\) [\#974](https://github.com/nlohmann/json/issues/974)
|
||||
- Segfault on direct initializing json object [\#973](https://github.com/nlohmann/json/issues/973)
|
||||
- Segmentation fault on G++ when trying to assign json string literal to custom json type. [\#972](https://github.com/nlohmann/json/issues/972)
|
||||
- os\_defines.h:44:19: error: missing binary operator before token "\(" [\#970](https://github.com/nlohmann/json/issues/970)
|
||||
- Passing an iteration object by reference to a function [\#967](https://github.com/nlohmann/json/issues/967)
|
||||
- Json and fmt::lib's format\_arg\(\) [\#964](https://github.com/nlohmann/json/issues/964)
|
||||
|
||||
- Allowing for user-defined string type in lexer/parser [\#1009](https://github.com/nlohmann/json/pull/1009) ([nlohmann](https://github.com/nlohmann))
|
||||
- dump to alternative string type, as defined in basic\_json template [\#1006](https://github.com/nlohmann/json/pull/1006) ([agrianius](https://github.com/agrianius))
|
||||
- Fix memory leak during parser callback [\#1001](https://github.com/nlohmann/json/pull/1001) ([nlohmann](https://github.com/nlohmann))
|
||||
- fixed misprinted condition detected by PVS Studio. [\#992](https://github.com/nlohmann/json/pull/992) ([bogemic](https://github.com/bogemic))
|
||||
- Fix/basic json conversion [\#986](https://github.com/nlohmann/json/pull/986) ([theodelrieu](https://github.com/theodelrieu))
|
||||
- Make integration section concise [\#981](https://github.com/nlohmann/json/pull/981) ([wla80](https://github.com/wla80))
|
||||
|
||||
## [v3.1.1](https://github.com/nlohmann/json/releases/tag/v3.1.1) (2018-02-13)
|
||||
[Full Changelog](https://github.com/nlohmann/json/compare/v3.1.0...v3.1.1)
|
||||
|
||||
- Updation of child object isn't reflected in parent Object [\#968](https://github.com/nlohmann/json/issues/968)
|
||||
- How to add user defined C++ path to sublime text [\#966](https://github.com/nlohmann/json/issues/966)
|
||||
- fast number parsing [\#965](https://github.com/nlohmann/json/issues/965)
|
||||
- With non-unique keys, later stored entries are not taken into account anymore [\#963](https://github.com/nlohmann/json/issues/963)
|
||||
- Timeout \(OSS-Fuzz 6034\) [\#962](https://github.com/nlohmann/json/issues/962)
|
||||
- Incorrect parsing of indefinite length CBOR strings. [\#961](https://github.com/nlohmann/json/issues/961)
|
||||
- Reload a json file at runtime without emptying my std::ifstream [\#959](https://github.com/nlohmann/json/issues/959)
|
||||
- Split headers should be part of the release [\#956](https://github.com/nlohmann/json/issues/956)
|
||||
- Coveralls shows no coverage data [\#953](https://github.com/nlohmann/json/issues/953)
|
||||
- Feature request: Implicit conversion to bool [\#951](https://github.com/nlohmann/json/issues/951)
|
||||
- converting json to vector of type with templated constructor [\#924](https://github.com/nlohmann/json/issues/924)
|
||||
- No structured bindings support? [\#901](https://github.com/nlohmann/json/issues/901)
|
||||
- \[Request\] Macro generating from\_json\(\) and to\_json\(\) [\#895](https://github.com/nlohmann/json/issues/895)
|
||||
- basic\_json::value throws exception instead of returning default value [\#871](https://github.com/nlohmann/json/issues/871)
|
||||
|
||||
- Fix constraints on from\_json\(CompatibleArrayType\) [\#969](https://github.com/nlohmann/json/pull/969) ([theodelrieu](https://github.com/theodelrieu))
|
||||
- Make coveralls watch the include folder [\#957](https://github.com/nlohmann/json/pull/957) ([theodelrieu](https://github.com/theodelrieu))
|
||||
- Fix links in README.md [\#955](https://github.com/nlohmann/json/pull/955) ([patrikhuber](https://github.com/patrikhuber))
|
||||
- Add a note about installing the library with cget [\#954](https://github.com/nlohmann/json/pull/954) ([pfultz2](https://github.com/pfultz2))
|
||||
|
||||
## [v3.1.0](https://github.com/nlohmann/json/releases/tag/v3.1.0) (2018-02-01)
|
||||
[Full Changelog](https://github.com/nlohmann/json/compare/v3.0.1...v3.1.0)
|
||||
|
||||
- Order of the elements in JSON object [\#952](https://github.com/nlohmann/json/issues/952)
|
||||
- I have a proposal [\#949](https://github.com/nlohmann/json/issues/949)
|
||||
- VERSION define\(s\) [\#948](https://github.com/nlohmann/json/issues/948)
|
||||
- v3.0.1 compile error in icc 16.0.4 [\#947](https://github.com/nlohmann/json/issues/947)
|
||||
- Use in VS2017 15.5.5 [\#946](https://github.com/nlohmann/json/issues/946)
|
||||
- Process for reporting Security Bugs? [\#945](https://github.com/nlohmann/json/issues/945)
|
||||
- Please expose a NLOHMANN\_JSON\_VERSION macro [\#943](https://github.com/nlohmann/json/issues/943)
|
||||
- Change header include directory to nlohmann/json [\#942](https://github.com/nlohmann/json/issues/942)
|
||||
- string\_type in binary\_reader [\#941](https://github.com/nlohmann/json/issues/941)
|
||||
- compile error with clang 5.0 -std=c++1z and no string\_view [\#939](https://github.com/nlohmann/json/issues/939)
|
||||
- Allow overriding JSON\_THROW to something else than abort\(\) [\#938](https://github.com/nlohmann/json/issues/938)
|
||||
- Handle invalid string in Json file [\#937](https://github.com/nlohmann/json/issues/937)
|
||||
- Unused variable 'kMinExp' [\#935](https://github.com/nlohmann/json/issues/935)
|
||||
- yytext is already defined [\#933](https://github.com/nlohmann/json/issues/933)
|
||||
- Equality operator fails [\#931](https://github.com/nlohmann/json/issues/931)
|
||||
- use in visual studio 2015 [\#929](https://github.com/nlohmann/json/issues/929)
|
||||
- Relative includes of json\_fwd.hpp in detail/meta.hpp. \[Develop branch\] [\#928](https://github.com/nlohmann/json/issues/928)
|
||||
- GCC 7.x issue [\#926](https://github.com/nlohmann/json/issues/926)
|
||||
- json\_fwd.hpp not installed [\#923](https://github.com/nlohmann/json/issues/923)
|
||||
- Use Google Benchmarks [\#921](https://github.com/nlohmann/json/issues/921)
|
||||
- Move class json\_pointer to separate file [\#920](https://github.com/nlohmann/json/issues/920)
|
||||
- Unable to locate 'to\_json\(\)' and 'from\_json\(\)' methods in the same namespace [\#917](https://github.com/nlohmann/json/issues/917)
|
||||
- \[answered\]Read key1 from .value example [\#914](https://github.com/nlohmann/json/issues/914)
|
||||
- Don't use `define private public` in test files [\#913](https://github.com/nlohmann/json/issues/913)
|
||||
- value\(\) template argument type deduction [\#912](https://github.com/nlohmann/json/issues/912)
|
||||
- Installation path is incorrect [\#910](https://github.com/nlohmann/json/issues/910)
|
||||
- H [\#909](https://github.com/nlohmann/json/issues/909)
|
||||
- Build failure using clang 5 [\#908](https://github.com/nlohmann/json/issues/908)
|
||||
- Amalgate [\#907](https://github.com/nlohmann/json/issues/907)
|
||||
- Update documentation and tests wrt. split headers [\#906](https://github.com/nlohmann/json/issues/906)
|
||||
- Lib not working on ubuntu 16.04 [\#905](https://github.com/nlohmann/json/issues/905)
|
||||
- Problem when writing to file. [\#904](https://github.com/nlohmann/json/issues/904)
|
||||
- C2864 error when compiling with VS2015 and VS 2017 [\#903](https://github.com/nlohmann/json/issues/903)
|
||||
- \[json.exception.type\_error.304\] cannot use at\(\) with object [\#902](https://github.com/nlohmann/json/issues/902)
|
||||
- How do I forward nlohmann::json declaration? [\#899](https://github.com/nlohmann/json/issues/899)
|
||||
- How to effectively store binary data? [\#898](https://github.com/nlohmann/json/issues/898)
|
||||
- How to get the length of a JSON string without retrieving its std::string? [\#897](https://github.com/nlohmann/json/issues/897)
|
||||
- Regression Tests Failure using "ctest" [\#887](https://github.com/nlohmann/json/issues/887)
|
||||
- Discuss: add JSON Merge Patch \(RFC 7396\)? [\#877](https://github.com/nlohmann/json/issues/877)
|
||||
- Discuss: replace static "iterator\_wrapper" function with "items" member function [\#874](https://github.com/nlohmann/json/issues/874)
|
||||
- Make optional user-data available in from\_json [\#864](https://github.com/nlohmann/json/issues/864)
|
||||
- Casting to std::string not working in VS2015 [\#861](https://github.com/nlohmann/json/issues/861)
|
||||
- Sequential reading of JSON arrays [\#851](https://github.com/nlohmann/json/issues/851)
|
||||
- Idea: Handle Multimaps Better [\#816](https://github.com/nlohmann/json/issues/816)
|
||||
- Floating point rounding [\#777](https://github.com/nlohmann/json/issues/777)
|
||||
- Loss of precision when serializing \<double\> [\#360](https://github.com/nlohmann/json/issues/360)
|
||||
|
||||
- Templatize std::string in binary\_reader \#941 [\#950](https://github.com/nlohmann/json/pull/950) ([kaidokert](https://github.com/kaidokert))
|
||||
- fix cmake install directory \(for real this time\) [\#944](https://github.com/nlohmann/json/pull/944) ([theodelrieu](https://github.com/theodelrieu))
|
||||
- Allow overriding THROW/CATCH/TRY macros with no-exceptions \#938 [\#940](https://github.com/nlohmann/json/pull/940) ([kaidokert](https://github.com/kaidokert))
|
||||
- Removed compiler warning about unused variable 'kMinExp' [\#936](https://github.com/nlohmann/json/pull/936) ([zerodefect](https://github.com/zerodefect))
|
||||
- Fix a typo in README.md [\#930](https://github.com/nlohmann/json/pull/930) ([Pipeliner](https://github.com/Pipeliner))
|
||||
- Howto installation of json\_fwd.hpp \(fixes \#923\) [\#925](https://github.com/nlohmann/json/pull/925) ([zerodefect](https://github.com/zerodefect))
|
||||
- fix sfinae on basic\_json UDT constructor [\#919](https://github.com/nlohmann/json/pull/919) ([theodelrieu](https://github.com/theodelrieu))
|
||||
- Floating-point formatting [\#915](https://github.com/nlohmann/json/pull/915) ([abolz](https://github.com/abolz))
|
||||
- Fix/cmake install [\#911](https://github.com/nlohmann/json/pull/911) ([theodelrieu](https://github.com/theodelrieu))
|
||||
- fix link to the documentation of the emplace function [\#900](https://github.com/nlohmann/json/pull/900) ([Dobiasd](https://github.com/Dobiasd))
|
||||
- JSON Merge Patch \(RFC 7396\) [\#876](https://github.com/nlohmann/json/pull/876) ([nlohmann](https://github.com/nlohmann))
|
||||
- Refactor/split it [\#700](https://github.com/nlohmann/json/pull/700) ([theodelrieu](https://github.com/theodelrieu))
|
||||
|
||||
## [v3.0.1](https://github.com/nlohmann/json/releases/tag/v3.0.1) (2017-12-29)
|
||||
[Full Changelog](https://github.com/nlohmann/json/compare/v3.0.0...v3.0.1)
|
||||
|
||||
@@ -972,6 +49,7 @@ All notable changes to this project will be documented in this file. This projec
|
||||
- using dump\(\) when std::wstring is StringType with VS2017 [\#836](https://github.com/nlohmann/json/issues/836)
|
||||
- Show the path of the currently parsed value when an error occurs [\#835](https://github.com/nlohmann/json/issues/835)
|
||||
- Repetitive data type while reading [\#833](https://github.com/nlohmann/json/issues/833)
|
||||
- Stack-overflow \(OSS-Fuzz 4234\) [\#832](https://github.com/nlohmann/json/issues/832)
|
||||
- Storing multiple types inside map [\#831](https://github.com/nlohmann/json/issues/831)
|
||||
- Application terminating [\#830](https://github.com/nlohmann/json/issues/830)
|
||||
- Missing CMake hunter package? [\#828](https://github.com/nlohmann/json/issues/828)
|
||||
@@ -1068,6 +146,7 @@ All notable changes to this project will be documented in this file. This projec
|
||||
- Compile-Error C2100 \(MS VS2015\) in line 887 json.hpp [\#719](https://github.com/nlohmann/json/issues/719)
|
||||
- from\_json not working for boost::optional example [\#718](https://github.com/nlohmann/json/issues/718)
|
||||
- about from\_json and to\_json function [\#717](https://github.com/nlohmann/json/issues/717)
|
||||
- How to deserialize array with derived objects [\#716](https://github.com/nlohmann/json/issues/716)
|
||||
- How to detect parse failure? [\#715](https://github.com/nlohmann/json/issues/715)
|
||||
- Parse throw std::ios\_base::failure exception when failbit set to true [\#714](https://github.com/nlohmann/json/issues/714)
|
||||
- Is there a way of format just making a pretty print without changing the key's orders ? [\#713](https://github.com/nlohmann/json/issues/713)
|
||||
@@ -1574,7 +653,7 @@ All notable changes to this project will be documented in this file. This projec
|
||||
- Compilation error. [\#273](https://github.com/nlohmann/json/issues/273)
|
||||
- dump\(\) performance degradation in v2 [\#272](https://github.com/nlohmann/json/issues/272)
|
||||
|
||||
- fixed a tiny typo [\#271](https://github.com/nlohmann/json/pull/271) ([feroldi](https://github.com/feroldi))
|
||||
- fixed a tiny typo [\#271](https://github.com/nlohmann/json/pull/271) ([thelostt](https://github.com/thelostt))
|
||||
|
||||
## [v2.0.0](https://github.com/nlohmann/json/releases/tag/v2.0.0) (2016-06-23)
|
||||
[Full Changelog](https://github.com/nlohmann/json/compare/v1.1.0...v2.0.0)
|
||||
@@ -1582,6 +661,7 @@ All notable changes to this project will be documented in this file. This projec
|
||||
- json::diff generates incorrect patch when removing multiple array elements. [\#269](https://github.com/nlohmann/json/issues/269)
|
||||
- Docs - What does Json\[key\] return? [\#267](https://github.com/nlohmann/json/issues/267)
|
||||
- Compiler Errors With JSON.hpp [\#265](https://github.com/nlohmann/json/issues/265)
|
||||
- Throw exception instead of crashing my app [\#264](https://github.com/nlohmann/json/issues/264)
|
||||
- Ambiguous push\_back and operator+= overloads [\#263](https://github.com/nlohmann/json/issues/263)
|
||||
- Preseving order of items in json [\#262](https://github.com/nlohmann/json/issues/262)
|
||||
- '\' char problem in strings [\#261](https://github.com/nlohmann/json/issues/261)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013-2019 Niels Lohmann
|
||||
Copyright (c) 2013-2017 Niels Lohmann
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
489
Makefile
489
Makefile
@@ -1,56 +1,20 @@
|
||||
.PHONY: pretty clean ChangeLog.md release
|
||||
.PHONY: pretty clean ChangeLog.md
|
||||
|
||||
##########################################################################
|
||||
# configuration
|
||||
##########################################################################
|
||||
|
||||
# directory to recent compiler binaries
|
||||
COMPILER_DIR=/Users/niels/Documents/projects/compilers/local/bin
|
||||
|
||||
# find GNU sed to use `-i` parameter
|
||||
SED:=$(shell command -v gsed || which sed)
|
||||
|
||||
|
||||
##########################################################################
|
||||
# source files
|
||||
##########################################################################
|
||||
|
||||
# the list of sources in the include folder
|
||||
SRCS=$(shell find include -type f | sort)
|
||||
|
||||
# the single header (amalgamated from the source files)
|
||||
AMALGAMATED_FILE=single_include/nlohmann/json.hpp
|
||||
|
||||
|
||||
##########################################################################
|
||||
# documentation of the Makefile's targets
|
||||
##########################################################################
|
||||
|
||||
# main target
|
||||
all:
|
||||
@echo "amalgamate - amalgamate file single_include/nlohmann/json.hpp from the include/nlohmann sources"
|
||||
@echo "ChangeLog.md - generate ChangeLog file"
|
||||
@echo "check - compile and execute test suite"
|
||||
@echo "check-amalgamation - check whether sources have been amalgamated"
|
||||
@echo "check-fast - compile and execute test suite (skip long-running tests)"
|
||||
@echo "clean - remove built files"
|
||||
@echo "coverage - create coverage information with lcov"
|
||||
@echo "coverage-fast - create coverage information with fastcov"
|
||||
@echo "cppcheck - analyze code with cppcheck"
|
||||
@echo "cpplint - analyze code with cpplint"
|
||||
@echo "clang_tidy - analyze code with Clang-Tidy"
|
||||
@echo "clang_analyze - analyze code with Clang-Analyzer"
|
||||
@echo "doctest - compile example files and check their output"
|
||||
@echo "fuzz_testing - prepare fuzz testing of the JSON parser"
|
||||
@echo "fuzz_testing_bson - prepare fuzz testing of the BSON parser"
|
||||
@echo "fuzz_testing_cbor - prepare fuzz testing of the CBOR parser"
|
||||
@echo "fuzz_testing_msgpack - prepare fuzz testing of the MessagePack parser"
|
||||
@echo "fuzz_testing_ubjson - prepare fuzz testing of the UBJSON parser"
|
||||
@echo "json_unit - create single-file test executable"
|
||||
@echo "pedantic_clang - run Clang with maximal warning flags"
|
||||
@echo "pedantic_gcc - run GCC with maximal warning flags"
|
||||
@echo "pretty - beautify code with Artistic Style"
|
||||
@echo "run_benchmarks - build and run benchmarks"
|
||||
|
||||
|
||||
##########################################################################
|
||||
@@ -65,32 +29,31 @@ json_unit:
|
||||
check:
|
||||
$(MAKE) check -C test
|
||||
|
||||
# run unit tests and skip expensive tests
|
||||
check-fast:
|
||||
$(MAKE) check -C test TEST_PATTERN=""
|
||||
|
||||
# clean up
|
||||
clean:
|
||||
rm -fr json_unit json_benchmarks fuzz fuzz-testing *.dSYM test/*.dSYM
|
||||
rm -fr benchmarks/files/numbers/*.json
|
||||
rm -fr build_coverage
|
||||
$(MAKE) clean -Cdoc
|
||||
$(MAKE) clean -Ctest
|
||||
$(MAKE) clean -Cbenchmarks
|
||||
|
||||
|
||||
##########################################################################
|
||||
# coverage
|
||||
##########################################################################
|
||||
|
||||
coverage:
|
||||
rm -fr build_coverage
|
||||
mkdir build_coverage
|
||||
cd build_coverage ; CXX=g++-8 cmake .. -GNinja -DJSON_Coverage=ON -DJSON_MultipleHeaders=ON
|
||||
cd build_coverage ; CXX=g++-5 cmake .. -GNinja -DJSON_Coverage=ON
|
||||
cd build_coverage ; ninja
|
||||
cd build_coverage ; ctest -E '.*_default' -j10
|
||||
cd build_coverage ; ctest
|
||||
cd build_coverage ; ninja lcov_html
|
||||
open build_coverage/test/html/index.html
|
||||
|
||||
coverage-fast:
|
||||
rm -fr build_coverage
|
||||
mkdir build_coverage
|
||||
cd build_coverage ; CXX=g++-9 cmake .. -GNinja -DJSON_Coverage=ON -DJSON_MultipleHeaders=ON
|
||||
cd build_coverage ; ninja
|
||||
cd build_coverage ; ctest -E '.*_default' -j10
|
||||
cd build_coverage ; ninja fastcov_html
|
||||
open build_coverage/test/html/index.html
|
||||
|
||||
##########################################################################
|
||||
# documentation tests
|
||||
@@ -106,267 +69,91 @@ doctest:
|
||||
##########################################################################
|
||||
|
||||
# calling Clang with all warnings, except:
|
||||
# -Wno-c++2a-compat: u8 literals will behave differently in C++20...
|
||||
# -Wno-deprecated-declarations: the library deprecated some functions
|
||||
# -Wno-documentation-unknown-command: code uses user-defined commands like @complexity
|
||||
# -Wno-exit-time-destructors: warning in json code triggered by NLOHMANN_JSON_SERIALIZE_ENUM
|
||||
# -Wno-float-equal: not all comparisons in the tests can be replaced by Approx
|
||||
# -Wno-exit-time-destructors: warning in Catch code
|
||||
# -Wno-keyword-macro: unit-tests use "#define private public"
|
||||
# -Wno-padded: padding is nothing to warn about
|
||||
# -Wno-range-loop-analysis: items tests "for(const auto i...)"
|
||||
# -Wno-switch-enum -Wno-covered-switch-default: pedantic/contradicting warnings about switches
|
||||
# -Wno-deprecated-declarations: the library deprecated some functions
|
||||
# -Wno-weak-vtables: exception class is defined inline, but has virtual method
|
||||
# -Wno-range-loop-analysis: iterator_wrapper tests "for(const auto i...)"
|
||||
# -Wno-float-equal: not all comparisons in the tests can be replaced by Approx
|
||||
# -Wno-switch-enum -Wno-covered-switch-default: pedantic/contradicting warnings about switches
|
||||
# -Wno-padded: padding is nothing to warn about
|
||||
pedantic_clang:
|
||||
$(MAKE) json_unit CXX=c++ CXXFLAGS=" \
|
||||
$(MAKE) json_unit CXXFLAGS="\
|
||||
-std=c++11 -Wno-c++98-compat -Wno-c++98-compat-pedantic \
|
||||
-Werror \
|
||||
-Weverything \
|
||||
-Wno-c++2a-compat \
|
||||
-Wno-deprecated-declarations \
|
||||
-Wno-documentation-unknown-command \
|
||||
-Wno-exit-time-destructors \
|
||||
-Wno-float-equal \
|
||||
-Wno-keyword-macro \
|
||||
-Wno-padded \
|
||||
-Wno-deprecated-declarations \
|
||||
-Wno-weak-vtables \
|
||||
-Wno-range-loop-analysis \
|
||||
-Wno-float-equal \
|
||||
-Wno-switch-enum -Wno-covered-switch-default \
|
||||
-Wno-weak-vtables"
|
||||
-Wno-padded"
|
||||
|
||||
# calling GCC with most warnings
|
||||
pedantic_gcc:
|
||||
$(MAKE) json_unit CXX=/usr/local/bin/g++-9 CXXFLAGS=" \
|
||||
$(MAKE) json_unit CXXFLAGS="\
|
||||
-std=c++11 \
|
||||
-Waddress \
|
||||
-Waddress-of-packed-member \
|
||||
-Waggressive-loop-optimizations \
|
||||
-Waligned-new=all \
|
||||
-Wall \
|
||||
-Walloc-zero \
|
||||
-Wno-deprecated-declarations \
|
||||
-Werror \
|
||||
-Wall -Wpedantic -Wextra \
|
||||
-Walloca \
|
||||
-Warray-bounds \
|
||||
-Warray-bounds=2 \
|
||||
-Wattribute-alias=2 \
|
||||
-Wattribute-warning \
|
||||
-Wattributes \
|
||||
-Wbool-compare \
|
||||
-Wbool-operation \
|
||||
-Wbuiltin-declaration-mismatch \
|
||||
-Wbuiltin-macro-redefined \
|
||||
-Wcannot-profile \
|
||||
-Wcast-align \
|
||||
-Wcast-function-type \
|
||||
-Wcast-qual \
|
||||
-Wcatch-value=3 \
|
||||
-Wcast-qual -Wcast-align \
|
||||
-Wchar-subscripts \
|
||||
-Wclass-conversion \
|
||||
-Wclass-memaccess \
|
||||
-Wclobbered \
|
||||
-Wcomment \
|
||||
-Wcomments \
|
||||
-Wconditionally-supported \
|
||||
-Wconversion \
|
||||
-Wconversion-null \
|
||||
-Wcoverage-mismatch \
|
||||
-Wcpp \
|
||||
-Wctor-dtor-privacy \
|
||||
-Wdangling-else \
|
||||
-Wdate-time \
|
||||
-Wdelete-incomplete \
|
||||
-Wdelete-non-virtual-dtor \
|
||||
-Wdeprecated \
|
||||
-Wdeprecated-copy \
|
||||
-Wdeprecated-copy-dtor \
|
||||
-Wdeprecated-declarations \
|
||||
-Wdisabled-optimization \
|
||||
-Wdiv-by-zero \
|
||||
-Wdouble-promotion \
|
||||
-Wduplicated-branches \
|
||||
-Wduplicated-cond \
|
||||
-Weffc++ \
|
||||
-Wempty-body \
|
||||
-Wendif-labels \
|
||||
-Wenum-compare \
|
||||
-Wexpansion-to-defined \
|
||||
-Werror \
|
||||
-Wextra \
|
||||
-Wextra-semi \
|
||||
-Wfloat-conversion \
|
||||
-Wformat \
|
||||
-Wformat-contains-nul \
|
||||
-Wformat-extra-args \
|
||||
-Wformat-nonliteral \
|
||||
-Wformat-overflow=2 \
|
||||
-Wformat-security \
|
||||
-Wformat-signedness \
|
||||
-Wformat-truncation=2 \
|
||||
-Wformat-y2k \
|
||||
-Wformat-zero-length \
|
||||
-Wformat=2 \
|
||||
-Wframe-address \
|
||||
-Wfree-nonheap-object \
|
||||
-Whsa \
|
||||
-Wif-not-aligned \
|
||||
-Wignored-attributes \
|
||||
-Wignored-qualifiers \
|
||||
-Wno-ignored-qualifiers \
|
||||
-Wimplicit-fallthrough=5 \
|
||||
-Winherited-variadic-ctor \
|
||||
-Winit-list-lifetime \
|
||||
-Winit-self \
|
||||
-Winline \
|
||||
-Wint-in-bool-context \
|
||||
-Wint-to-pointer-cast \
|
||||
-Winvalid-memory-model \
|
||||
-Winvalid-offsetof \
|
||||
-Winvalid-pch \
|
||||
-Wliteral-suffix \
|
||||
-Wlogical-not-parentheses \
|
||||
-Wlogical-op \
|
||||
-Wlto-type-mismatch \
|
||||
-Wmain \
|
||||
-Wmaybe-uninitialized \
|
||||
-Wmemset-elt-size \
|
||||
-Wmemset-transposed-args \
|
||||
-Wmisleading-indentation \
|
||||
-Wmissing-attributes \
|
||||
-Wmissing-braces \
|
||||
-Wmissing-declarations \
|
||||
-Wmissing-field-initializers \
|
||||
-Wmissing-format-attribute \
|
||||
-Wmissing-include-dirs \
|
||||
-Wmissing-noreturn \
|
||||
-Wmissing-profile \
|
||||
-Wmultichar \
|
||||
-Wmultiple-inheritance \
|
||||
-Wmultistatement-macros \
|
||||
-Wnarrowing \
|
||||
-Wno-deprecated-declarations \
|
||||
-Wno-float-equal \
|
||||
-Wno-long-long \
|
||||
-Wno-namespaces \
|
||||
-Wno-padded \
|
||||
-Wno-switch-enum \
|
||||
-Wno-system-headers \
|
||||
-Wno-templates \
|
||||
-Wno-undef \
|
||||
-Wnoexcept \
|
||||
-Wnoexcept-type \
|
||||
-Wnon-template-friend \
|
||||
-Wnon-virtual-dtor \
|
||||
-Wnonnull \
|
||||
-Wnonnull-compare \
|
||||
-Wnonportable-cfstrings \
|
||||
-Wnormalized \
|
||||
-Wnull-dereference \
|
||||
-Wodr \
|
||||
-Wold-style-cast \
|
||||
-Wopenmp-simd \
|
||||
-Woverflow \
|
||||
-Woverlength-strings \
|
||||
-Woverloaded-virtual \
|
||||
-Wpacked \
|
||||
-Wpacked-bitfield-compat \
|
||||
-Wpacked-not-aligned \
|
||||
-Wparentheses \
|
||||
-Wpedantic \
|
||||
-Wpessimizing-move \
|
||||
-Wplacement-new=2 \
|
||||
-Wpmf-conversions \
|
||||
-Wpointer-arith \
|
||||
-Wpointer-compare \
|
||||
-Wpragmas \
|
||||
-Wprio-ctor-dtor \
|
||||
-Wpsabi \
|
||||
-Wredundant-decls \
|
||||
-Wredundant-move \
|
||||
-Wregister \
|
||||
-Wreorder \
|
||||
-Wrestrict \
|
||||
-Wreturn-local-addr \
|
||||
-Wreturn-type \
|
||||
-Wscalar-storage-order \
|
||||
-Wsequence-point \
|
||||
-Wshadow \
|
||||
-Wshadow-compatible-local \
|
||||
-Wshadow-local \
|
||||
-Wshadow=compatible-local \
|
||||
-Wshadow=global \
|
||||
-Wshadow=local \
|
||||
-Wshift-count-negative \
|
||||
-Wshift-count-overflow \
|
||||
-Wshift-negative-value \
|
||||
-Wshift-overflow=2 \
|
||||
-Wsign-compare \
|
||||
-Wsign-conversion \
|
||||
-Wsign-promo \
|
||||
-Wsized-deallocation \
|
||||
-Wsizeof-array-argument \
|
||||
-Wsizeof-pointer-div \
|
||||
-Wsizeof-pointer-memaccess \
|
||||
-Wstack-protector \
|
||||
-Wstrict-aliasing=3 \
|
||||
-Wstrict-null-sentinel \
|
||||
-Wstrict-overflow=5 \
|
||||
-Wstringop-overflow=4 \
|
||||
-Wstringop-truncation \
|
||||
-Wsubobject-linkage \
|
||||
-Wsuggest-attribute=cold \
|
||||
-Wsuggest-attribute=const \
|
||||
-Wsuggest-attribute=format \
|
||||
-Wsuggest-attribute=malloc \
|
||||
-Wsuggest-attribute=noreturn \
|
||||
-Wsuggest-attribute=pure \
|
||||
-Wsuggest-final-methods \
|
||||
-Wsuggest-final-types \
|
||||
-Wsuggest-override \
|
||||
-Wswitch \
|
||||
-Wswitch-bool \
|
||||
-Wswitch-default \
|
||||
-Wswitch-unreachable \
|
||||
-Wsync-nand \
|
||||
-Wsynth \
|
||||
-Wtautological-compare \
|
||||
-Wterminate \
|
||||
-Wtrampolines \
|
||||
-Wtrigraphs \
|
||||
-Wtype-limits \
|
||||
-Wuninitialized \
|
||||
-Wunknown-pragmas \
|
||||
-Wunreachable-code \
|
||||
-Wunsafe-loop-optimizations \
|
||||
-Wundef \
|
||||
-Wuninitialized -Wunknown-pragmas \
|
||||
-Wunused \
|
||||
-Wunused-but-set-parameter \
|
||||
-Wunused-but-set-variable \
|
||||
-Wunused-const-variable=2 \
|
||||
-Wunused-function \
|
||||
-Wunused-label \
|
||||
-Wunused-local-typedefs \
|
||||
-Wunused-macros \
|
||||
-Wunused-parameter \
|
||||
-Wunused-result \
|
||||
-Wunused-value \
|
||||
-Wunused-variable \
|
||||
-Wuseless-cast \
|
||||
-Wvarargs \
|
||||
-Wvariadic-macros \
|
||||
-Wvector-operation-performance \
|
||||
-Wvirtual-inheritance \
|
||||
-Wvirtual-move-assign \
|
||||
-Wvla \
|
||||
-Wvolatile-register-var \
|
||||
-Wwrite-strings \
|
||||
-Wzero-as-null-pointer-constant \
|
||||
"
|
||||
|
||||
##########################################################################
|
||||
# benchmarks
|
||||
##########################################################################
|
||||
|
||||
run_benchmarks:
|
||||
rm -fr build_benchmarks
|
||||
mkdir build_benchmarks
|
||||
cd build_benchmarks ; cmake ../benchmarks -GNinja -DCMAKE_BUILD_TYPE=Release
|
||||
cd build_benchmarks ; ninja
|
||||
cd build_benchmarks ; ./json_benchmarks
|
||||
-Wvariadic-macros"
|
||||
|
||||
##########################################################################
|
||||
# fuzzing
|
||||
@@ -381,14 +168,6 @@ fuzz_testing:
|
||||
find test/data/json_tests -size -5k -name *json | xargs -I{} cp "{}" fuzz-testing/testcases
|
||||
@echo "Execute: afl-fuzz -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzzer"
|
||||
|
||||
fuzz_testing_bson:
|
||||
rm -fr fuzz-testing
|
||||
mkdir -p fuzz-testing fuzz-testing/testcases fuzz-testing/out
|
||||
$(MAKE) parse_bson_fuzzer -C test CXX=afl-clang++
|
||||
mv test/parse_bson_fuzzer fuzz-testing/fuzzer
|
||||
find test/data -size -5k -name *.bson | xargs -I{} cp "{}" fuzz-testing/testcases
|
||||
@echo "Execute: afl-fuzz -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzzer"
|
||||
|
||||
fuzz_testing_cbor:
|
||||
rm -fr fuzz-testing
|
||||
mkdir -p fuzz-testing fuzz-testing/testcases fuzz-testing/out
|
||||
@@ -405,14 +184,6 @@ fuzz_testing_msgpack:
|
||||
find test/data -size -5k -name *.msgpack | xargs -I{} cp "{}" fuzz-testing/testcases
|
||||
@echo "Execute: afl-fuzz -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzzer"
|
||||
|
||||
fuzz_testing_ubjson:
|
||||
rm -fr fuzz-testing
|
||||
mkdir -p fuzz-testing fuzz-testing/testcases fuzz-testing/out
|
||||
$(MAKE) parse_ubjson_fuzzer -C test CXX=afl-clang++
|
||||
mv test/parse_ubjson_fuzzer fuzz-testing/fuzzer
|
||||
find test/data -size -5k -name *.ubjson | xargs -I{} cp "{}" fuzz-testing/testcases
|
||||
@echo "Execute: afl-fuzz -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzzer"
|
||||
|
||||
fuzzing-start:
|
||||
afl-fuzz -S fuzzer1 -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzzer > /dev/null &
|
||||
afl-fuzz -S fuzzer2 -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzzer > /dev/null &
|
||||
@@ -427,203 +198,37 @@ fuzzing-stop:
|
||||
-killall fuzzer
|
||||
-killall afl-fuzz
|
||||
|
||||
|
||||
##########################################################################
|
||||
# Static analysis
|
||||
# static analyzer
|
||||
##########################################################################
|
||||
|
||||
# call cppcheck <http://cppcheck.sourceforge.net>
|
||||
# Note: this target is called by Travis
|
||||
# call cppcheck on the main header file
|
||||
cppcheck:
|
||||
cppcheck --enable=warning --inline-suppr --inconclusive --force --std=c++11 $(AMALGAMATED_FILE) --error-exitcode=1
|
||||
|
||||
# call Clang Static Analyzer <https://clang-analyzer.llvm.org>
|
||||
clang_analyze:
|
||||
rm -fr clang_analyze_build
|
||||
mkdir clang_analyze_build
|
||||
cd clang_analyze_build ; CCC_CXX=$(COMPILER_DIR)/clang++ CXX=$(COMPILER_DIR)/clang++ $(COMPILER_DIR)/scan-build cmake .. -GNinja
|
||||
cd clang_analyze_build ; \
|
||||
$(COMPILER_DIR)/scan-build \
|
||||
-enable-checker alpha.core.BoolAssignment,alpha.core.CallAndMessageUnInitRefArg,alpha.core.CastSize,alpha.core.CastToStruct,alpha.core.Conversion,alpha.core.DynamicTypeChecker,alpha.core.FixedAddr,alpha.core.PointerArithm,alpha.core.PointerSub,alpha.core.SizeofPtr,alpha.core.StackAddressAsyncEscape,alpha.core.TestAfterDivZero,alpha.deadcode.UnreachableCode,core.builtin.BuiltinFunctions,core.builtin.NoReturnFunctions,core.CallAndMessage,core.DivideZero,core.DynamicTypePropagation,core.NonnilStringConstants,core.NonNullParamChecker,core.NullDereference,core.StackAddressEscape,core.UndefinedBinaryOperatorResult,core.uninitialized.ArraySubscript,core.uninitialized.Assign,core.uninitialized.Branch,core.uninitialized.CapturedBlockVariable,core.uninitialized.UndefReturn,core.VLASize,cplusplus.InnerPointer,cplusplus.Move,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,cplusplus.SelfAssignment,deadcode.DeadStores,nullability.NullableDereferenced,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull \
|
||||
--use-c++=$(COMPILER_DIR)/clang++ -analyze-headers -o report ninja
|
||||
open clang_analyze_build/report/*/index.html
|
||||
|
||||
# call cpplint <https://github.com/cpplint/cpplint>
|
||||
# Note: some errors expected due to false positives
|
||||
cpplint:
|
||||
third_party/cpplint/cpplint.py \
|
||||
--filter=-whitespace,-legal,-readability/alt_tokens,-runtime/references,-runtime/explicit \
|
||||
--quiet --recursive $(SRCS)
|
||||
|
||||
# call Clang-Tidy <https://clang.llvm.org/extra/clang-tidy/>
|
||||
clang_tidy:
|
||||
$(COMPILER_DIR)/clang-tidy $(AMALGAMATED_FILE) -- -Iinclude -std=c++11
|
||||
|
||||
# call PVS-Studio Analyzer <https://www.viva64.com/en/pvs-studio/>
|
||||
pvs_studio:
|
||||
rm -fr pvs_studio_build
|
||||
mkdir pvs_studio_build
|
||||
cd pvs_studio_build ; cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=On
|
||||
cd pvs_studio_build ; pvs-studio-analyzer analyze -j 10
|
||||
cd pvs_studio_build ; plog-converter -a'GA:1,2;64:1;CS' -t fullhtml PVS-Studio.log -o pvs
|
||||
open pvs_studio_build/pvs/index.html
|
||||
|
||||
# call Infer <https://fbinfer.com> static analyzer
|
||||
infer:
|
||||
rm -fr infer_build
|
||||
mkdir infer_build
|
||||
cd infer_build ; infer compile -- cmake .. ; infer run -- make -j 4
|
||||
|
||||
# call OCLint <http://oclint.org> static analyzer
|
||||
oclint:
|
||||
oclint $(SRCS) -report-type html -enable-global-analysis -o oclint_report.html -max-priority-1=10000 -max-priority-2=10000 -max-priority-3=10000 -- -std=c++11 -Iinclude
|
||||
open oclint_report.html
|
||||
|
||||
# execute the test suite with Clang sanitizers (address and undefined behavior)
|
||||
clang_sanitize:
|
||||
rm -fr clang_sanitize_build
|
||||
mkdir clang_sanitize_build
|
||||
cd clang_sanitize_build ; CXX=$(COMPILER_DIR)/clang++ cmake .. -DJSON_Sanitizer=On -DJSON_MultipleHeaders=ON -GNinja
|
||||
cd clang_sanitize_build ; ninja
|
||||
cd clang_sanitize_build ; ctest -E '.*_default' -j10
|
||||
cppcheck --enable=warning --inconclusive --force --std=c++11 src/json.hpp --error-exitcode=1
|
||||
|
||||
|
||||
##########################################################################
|
||||
# Code format and source amalgamation
|
||||
# maintainer targets
|
||||
##########################################################################
|
||||
|
||||
# call the Artistic Style pretty printer on all source files
|
||||
# pretty printer
|
||||
pretty:
|
||||
astyle \
|
||||
--style=allman \
|
||||
--indent=spaces=4 \
|
||||
--indent-modifiers \
|
||||
--indent-switches \
|
||||
--indent-preproc-block \
|
||||
--indent-preproc-define \
|
||||
--indent-col1-comments \
|
||||
--pad-oper \
|
||||
--pad-header \
|
||||
--align-pointer=type \
|
||||
--align-reference=type \
|
||||
--add-brackets \
|
||||
--convert-tabs \
|
||||
--close-templates \
|
||||
--lineend=linux \
|
||||
--preserve-date \
|
||||
--suffix=none \
|
||||
--formatted \
|
||||
$(SRCS) $(AMALGAMATED_FILE) test/src/*.cpp benchmarks/src/benchmarks.cpp doc/examples/*.cpp
|
||||
|
||||
# create single header file
|
||||
amalgamate: $(AMALGAMATED_FILE)
|
||||
|
||||
# call the amalgamation tool and pretty print
|
||||
$(AMALGAMATED_FILE): $(SRCS)
|
||||
third_party/amalgamate/amalgamate.py -c third_party/amalgamate/config.json -s . --verbose=yes
|
||||
$(MAKE) pretty
|
||||
|
||||
# check if file single_include/nlohmann/json.hpp has been amalgamated from the nlohmann sources
|
||||
# Note: this target is called by Travis
|
||||
check-amalgamation:
|
||||
@mv $(AMALGAMATED_FILE) $(AMALGAMATED_FILE)~
|
||||
@$(MAKE) amalgamate
|
||||
@diff $(AMALGAMATED_FILE) $(AMALGAMATED_FILE)~ || (echo "===================================================================\n Amalgamation required! Please read the contribution guidelines\n in file .github/CONTRIBUTING.md.\n===================================================================" ; mv $(AMALGAMATED_FILE)~ $(AMALGAMATED_FILE) ; false)
|
||||
@mv $(AMALGAMATED_FILE)~ $(AMALGAMATED_FILE)
|
||||
|
||||
# check if every header in nlohmann includes sufficient headers to be compiled individually
|
||||
check-single-includes:
|
||||
@for x in $(SRCS); do \
|
||||
echo "Checking self-sufficiency of $$x..." ; \
|
||||
echo "#include <$$x>\nint main() {}\n" | sed 's|include/||' > single_include_test.cpp; \
|
||||
$(CXX) $(CXXFLAGS) -Iinclude -std=c++11 single_include_test.cpp -o single_include_test; \
|
||||
rm -f single_include_test.cpp single_include_test; \
|
||||
done
|
||||
astyle --style=allman --indent=spaces=4 --indent-modifiers \
|
||||
--indent-switches --indent-preproc-block --indent-preproc-define \
|
||||
--indent-col1-comments --pad-oper --pad-header --align-pointer=type \
|
||||
--align-reference=type --add-brackets --convert-tabs --close-templates \
|
||||
--lineend=linux --preserve-date --suffix=none --formatted \
|
||||
src/json.hpp test/src/*.cpp \
|
||||
benchmarks/src/benchmarks.cpp doc/examples/*.cpp
|
||||
|
||||
|
||||
##########################################################################
|
||||
# CMake
|
||||
# changelog
|
||||
##########################################################################
|
||||
|
||||
# grep "^option" CMakeLists.txt test/CMakeLists.txt | sed 's/(/ /' | awk '{print $2}' | xargs
|
||||
|
||||
# check if all flags of our CMake files work
|
||||
check_cmake_flags_do:
|
||||
$(CMAKE_BINARY) --version
|
||||
for flag in '' JSON_BuildTests JSON_Install JSON_MultipleHeaders JSON_Sanitizer JSON_Valgrind JSON_NoExceptions JSON_Coverage; do \
|
||||
rm -fr cmake_build; \
|
||||
mkdir cmake_build; \
|
||||
echo "$(CMAKE_BINARY) .. -D$$flag=On" ; \
|
||||
cd cmake_build ; \
|
||||
CXX=g++-8 $(CMAKE_BINARY) .. -D$$flag=On -DCMAKE_CXX_COMPILE_FEATURES="cxx_std_11;cxx_range_for" -DCMAKE_CXX_FLAGS="-std=gnu++11" ; \
|
||||
test -f Makefile || exit 1 ; \
|
||||
cd .. ; \
|
||||
done;
|
||||
|
||||
# call target `check_cmake_flags_do` twice: once for minimal required CMake version 3.1.0 and once for the installed version
|
||||
check_cmake_flags:
|
||||
wget https://github.com/Kitware/CMake/releases/download/v3.1.0/cmake-3.1.0-Darwin64.tar.gz
|
||||
tar xfz cmake-3.1.0-Darwin64.tar.gz
|
||||
CMAKE_BINARY=$(abspath cmake-3.1.0-Darwin64/CMake.app/Contents/bin/cmake) $(MAKE) check_cmake_flags_do
|
||||
CMAKE_BINARY=$(shell which cmake) $(MAKE) check_cmake_flags_do
|
||||
|
||||
|
||||
##########################################################################
|
||||
# ChangeLog
|
||||
##########################################################################
|
||||
|
||||
# Create a ChangeLog based on the git log using the GitHub Changelog Generator
|
||||
# (<https://github.com/github-changelog-generator/github-changelog-generator>).
|
||||
|
||||
# variable to control the diffs between the last released version and the current repository state
|
||||
NEXT_VERSION ?= "unreleased"
|
||||
|
||||
ChangeLog.md:
|
||||
github_changelog_generator -o ChangeLog.md --simple-list --release-url https://github.com/nlohmann/json/releases/tag/%s --future-release $(NEXT_VERSION)
|
||||
$(SED) -i 's|https://github.com/nlohmann/json/releases/tag/HEAD|https://github.com/nlohmann/json/tree/HEAD|' ChangeLog.md
|
||||
$(SED) -i '2i All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/).' ChangeLog.md
|
||||
|
||||
|
||||
##########################################################################
|
||||
# Release files
|
||||
##########################################################################
|
||||
|
||||
# Create the files for a release and add signatures and hashes. We use `-X` to make the resulting ZIP file
|
||||
# reproducible, see <https://content.pivotal.io/blog/barriers-to-deterministic-reproducible-zip-files>.
|
||||
|
||||
release:
|
||||
rm -fr release_files
|
||||
mkdir release_files
|
||||
zip -9 --recurse-paths -X include.zip $(SRCS) $(AMALGAMATED_FILE) meson.build
|
||||
gpg --armor --detach-sig include.zip
|
||||
mv include.zip include.zip.asc release_files
|
||||
gpg --armor --detach-sig $(AMALGAMATED_FILE)
|
||||
cp $(AMALGAMATED_FILE) release_files
|
||||
mv $(AMALGAMATED_FILE).asc release_files
|
||||
cd release_files ; shasum -a 256 json.hpp > hashes.txt
|
||||
cd release_files ; shasum -a 256 include.zip >> hashes.txt
|
||||
|
||||
|
||||
##########################################################################
|
||||
# Maintenance
|
||||
##########################################################################
|
||||
|
||||
# clean up
|
||||
clean:
|
||||
rm -fr json_unit json_benchmarks fuzz fuzz-testing *.dSYM test/*.dSYM oclint_report.html
|
||||
rm -fr benchmarks/files/numbers/*.json
|
||||
rm -fr cmake-3.1.0-Darwin64.tar.gz cmake-3.1.0-Darwin64
|
||||
rm -fr build_coverage build_benchmarks fuzz-testing clang_analyze_build pvs_studio_build infer_build clang_sanitize_build cmake_build
|
||||
$(MAKE) clean -Cdoc
|
||||
$(MAKE) clean -Ctest
|
||||
|
||||
##########################################################################
|
||||
# Thirdparty code
|
||||
##########################################################################
|
||||
|
||||
update_hedley:
|
||||
rm -f include/nlohmann/thirdparty/hedley/hedley.hpp include/nlohmann/thirdparty/hedley/hedley_undef.hpp
|
||||
curl https://raw.githubusercontent.com/nemequ/hedley/master/hedley.h -o include/nlohmann/thirdparty/hedley/hedley.hpp
|
||||
gsed -i 's/HEDLEY_/JSON_HEDLEY_/g' include/nlohmann/thirdparty/hedley/hedley.hpp
|
||||
grep "[[:blank:]]*#[[:blank:]]*undef" include/nlohmann/thirdparty/hedley/hedley.hpp | grep -v "__" | sort | uniq | gsed 's/ //g' | gsed 's/undef/undef /g' > include/nlohmann/thirdparty/hedley/hedley_undef.hpp
|
||||
$(MAKE) amalgamate
|
||||
gsed -i 's|https://github.com/nlohmann/json/releases/tag/HEAD|https://github.com/nlohmann/json/tree/HEAD|' ChangeLog.md
|
||||
gsed -i '2i All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/).' ChangeLog.md
|
||||
|
||||
133
appveyor.yml
133
appveyor.yml
@@ -1,126 +1,27 @@
|
||||
version: '{build}'
|
||||
|
||||
os:
|
||||
- Visual Studio 2015
|
||||
- Visual Studio 2017
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
configuration: Debug
|
||||
platform: x86
|
||||
CXX_FLAGS: ""
|
||||
LINKER_FLAGS: ""
|
||||
GENERATOR: Visual Studio 14 2015
|
||||
- additional_flags: ""
|
||||
- additional_flags: "/permissive- /std:c++latest /utf-8"
|
||||
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
configuration: Debug
|
||||
platform: x86
|
||||
CXX_FLAGS: ""
|
||||
LINKER_FLAGS: ""
|
||||
GENERATOR: Visual Studio 15 2017
|
||||
matrix:
|
||||
exclude:
|
||||
- additional_flags: "/permissive- /std:c++latest /utf-8"
|
||||
os: Visual Studio 2015
|
||||
|
||||
init: []
|
||||
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
configuration: Debug
|
||||
platform: x86
|
||||
CXX_FLAGS: ""
|
||||
LINKER_FLAGS: ""
|
||||
GENERATOR: Visual Studio 16 2019
|
||||
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
configuration: Debug
|
||||
platform: x64
|
||||
CXX_FLAGS: ""
|
||||
LINKER_FLAGS: ""
|
||||
GENERATOR: Visual Studio 16 2019
|
||||
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
configuration: Debug
|
||||
COMPILER: mingw
|
||||
platform: x86
|
||||
CXX_FLAGS: ""
|
||||
LINKER_FLAGS: ""
|
||||
GENERATOR: Ninja
|
||||
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
configuration: Release
|
||||
COMPILER: mingw
|
||||
platform: x86
|
||||
CXX_FLAGS: ""
|
||||
LINKER_FLAGS: ""
|
||||
GENERATOR: Ninja
|
||||
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
configuration: Release
|
||||
platform: x86
|
||||
CXX_FLAGS: ""
|
||||
LINKER_FLAGS: ""
|
||||
GENERATOR: Visual Studio 14 2015
|
||||
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
configuration: Release
|
||||
platform: x86
|
||||
name: with_win_header
|
||||
CXX_FLAGS: ""
|
||||
LINKER_FLAGS: ""
|
||||
GENERATOR: Visual Studio 14 2015
|
||||
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
configuration: Release
|
||||
platform: x86
|
||||
CXX_FLAGS: "/permissive- /std:c++latest /utf-8"
|
||||
LINKER_FLAGS: ""
|
||||
GENERATOR: Visual Studio 15 2017
|
||||
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
configuration: Release
|
||||
platform: x86
|
||||
CXX_FLAGS: ""
|
||||
LINKER_FLAGS: ""
|
||||
GENERATOR: Visual Studio 16 2019
|
||||
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
configuration: Release
|
||||
platform: x64
|
||||
CXX_FLAGS: ""
|
||||
LINKER_FLAGS: ""
|
||||
GENERATOR: Visual Studio 14 2015
|
||||
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
configuration: Release
|
||||
platform: x64
|
||||
CXX_FLAGS: "/permissive- /std:c++latest /utf-8 /F4000000"
|
||||
LINKER_FLAGS: "/STACK:4000000"
|
||||
GENERATOR: Visual Studio 15 2017
|
||||
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
configuration: Release
|
||||
platform: x64
|
||||
CXX_FLAGS: ""
|
||||
LINKER_FLAGS: ""
|
||||
GENERATOR: Visual Studio 16 2019
|
||||
|
||||
init:
|
||||
- cmake --version
|
||||
- msbuild /version
|
||||
|
||||
install:
|
||||
- if "%COMPILER%"=="mingw" appveyor DownloadFile https://github.com/ninja-build/ninja/releases/download/v1.6.0/ninja-win.zip -FileName ninja.zip
|
||||
- if "%COMPILER%"=="mingw" 7z x ninja.zip -oC:\projects\deps\ninja > nul
|
||||
- if "%COMPILER%"=="mingw" set PATH=C:\projects\deps\ninja;%PATH%
|
||||
- if "%COMPILER%"=="mingw" set PATH=C:\mingw-w64\x86_64-7.3.0-posix-seh-rt_v5-rev0\mingw64\bin;%PATH%
|
||||
- if "%COMPILER%"=="mingw" g++ --version
|
||||
- if "%platform%"=="x86" set GENERATOR_PLATFORM=Win32
|
||||
|
||||
before_build:
|
||||
# for with_win_header build, inject the inclusion of Windows.h to the single-header library
|
||||
- ps: if ($env:name -Eq "with_win_header") { $header_path = "single_include\nlohmann\json.hpp" }
|
||||
- ps: if ($env:name -Eq "with_win_header") { "#include <Windows.h>`n" + (Get-Content $header_path | Out-String) | Set-Content $header_path }
|
||||
- if "%GENERATOR%"=="Ninja" (cmake . -G "%GENERATOR%" -DCMAKE_BUILD_TYPE="%configuration%" -DCMAKE_CXX_FLAGS="%CXX_FLAGS%" -DCMAKE_EXE_LINKER_FLAGS="%LINKER_FLAGS%" -DCMAKE_IGNORE_PATH="C:/Program Files/Git/usr/bin") else (cmake . -G "%GENERATOR%" -A "%GENERATOR_PLATFORM%" -DCMAKE_CXX_FLAGS="%CXX_FLAGS%" -DCMAKE_EXE_LINKER_FLAGS="%LINKER_FLAGS%" -DCMAKE_IGNORE_PATH="C:/Program Files/Git/usr/bin")
|
||||
install: []
|
||||
|
||||
build_script:
|
||||
- cmake --build . --config "%configuration%"
|
||||
- IF "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Visual Studio 2015" ( SET GEN="Visual Studio 14 2015") ELSE (SET GEN="Visual Studio 15 2017")
|
||||
- cmake . -G%GEN% -DCMAKE_CXX_FLAGS="%additional_flags%"
|
||||
- cmake --build . --config Release
|
||||
|
||||
test_script:
|
||||
- if "%configuration%"=="Release" ctest -C "%configuration%" -V -j
|
||||
# On Debug builds, skip test-unicode_all
|
||||
# as it is extremely slow to run and cause
|
||||
# occasional timeouts on AppVeyor.
|
||||
# More info: https://github.com/nlohmann/json/pull/1570
|
||||
- if "%configuration%"=="Debug" ctest --exclude-regex "test-unicode_all" -C "%configuration%" -V -j
|
||||
- ctest -C Release -V -j
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.8)
|
||||
project(JSON_Benchmarks LANGUAGES CXX)
|
||||
|
||||
# set compiler flags
|
||||
if((CMAKE_CXX_COMPILER_ID MATCHES GNU) OR (CMAKE_CXX_COMPILER_ID MATCHES Clang))
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto -DNDEBUG -O3")
|
||||
endif()
|
||||
|
||||
# configure Google Benchmarks
|
||||
set(BENCHMARK_ENABLE_TESTING OFF CACHE INTERNAL "" FORCE)
|
||||
add_subdirectory(thirdparty/benchmark)
|
||||
|
||||
# header directories
|
||||
include_directories(thirdparty)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/../single_include)
|
||||
|
||||
# copy test files to build folder
|
||||
file(COPY ${CMAKE_SOURCE_DIR}/data DESTINATION .)
|
||||
file(COPY ${CMAKE_SOURCE_DIR}/../test/data/regression/floats.json
|
||||
${CMAKE_SOURCE_DIR}/../test/data/regression/unsigned_ints.json
|
||||
${CMAKE_SOURCE_DIR}/../test/data/regression/signed_ints.json
|
||||
${CMAKE_SOURCE_DIR}/../test/data/regression/small_signed_ints.json
|
||||
DESTINATION data/numbers)
|
||||
|
||||
# benchmark binary
|
||||
add_executable(json_benchmarks src/benchmarks.cpp)
|
||||
target_compile_features(json_benchmarks PRIVATE cxx_std_11)
|
||||
target_link_libraries(json_benchmarks benchmark ${CMAKE_THREAD_LIBS_INIT})
|
||||
21
benchmarks/Makefile
Normal file
21
benchmarks/Makefile
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
#
|
||||
# Build/run json.hpp benchmarks, eg. CXX=g++-7 make
|
||||
#
|
||||
# The existing json_benchmarks did not allow optimization under some compilers
|
||||
#
|
||||
all: json_benchmarks json_benchmarks_simple number_jsons
|
||||
bash -c 'time ./json_benchmarks'
|
||||
bash -c 'time ./json_benchmarks_simple'
|
||||
|
||||
json_benchmarks: src/benchmarks.cpp ../src/json.hpp
|
||||
$(CXX) -std=c++11 -pthread $(CXXFLAGS) -DNDEBUG -O3 -flto -I thirdparty/benchpress -I thirdparty/cxxopts -I../src src/benchmarks.cpp $(LDFLAGS) -o $@
|
||||
|
||||
json_benchmarks_simple: src/benchmarks_simple.cpp ../src/json.hpp
|
||||
$(CXX) -std=c++11 $(CXXFLAGS) -DNDEBUG -O3 -flto -I../src $(<) $(LDFLAGS) -o $@
|
||||
|
||||
number_jsons:
|
||||
(test -e files/numbers/floats.json -a -e files/numbers/signed_ints.json -a -e files/numbers/unsigned_ints.json) || (cd files/numbers ; python generate.py)
|
||||
|
||||
clean:
|
||||
rm -f json_benchmarks json_benchmarks_simple files/numbers/*.json
|
||||
3
benchmarks/README.md
Normal file
3
benchmarks/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Bechmarks
|
||||
|
||||
Run `make` to compile and run a small set of benchmarks.
|
||||
25
benchmarks/files/numbers/generate.py
Executable file
25
benchmarks/files/numbers/generate.py
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import json
|
||||
import random
|
||||
import sys
|
||||
|
||||
random.seed(0)
|
||||
|
||||
# floats
|
||||
result_floats = []
|
||||
for x in range(0, 1000000):
|
||||
result_floats.append(random.uniform(-100000000.0, 100000000.0))
|
||||
json.dump(result_floats, open("floats.json", "w"), indent=2)
|
||||
|
||||
# unsigned integers
|
||||
result_uints = []
|
||||
for x in range(0, 1000000):
|
||||
result_uints.append(random.randint(0, 18446744073709551615))
|
||||
json.dump(result_uints, open("unsigned_ints.json", "w"), indent=2)
|
||||
|
||||
# signed integers
|
||||
result_sints = []
|
||||
for x in range(0, 1000000):
|
||||
result_sints.append(random.randint(-9223372036854775808, 9223372036854775807))
|
||||
json.dump(result_sints, open("signed_ints.json", "w"), indent=2)
|
||||
@@ -1,109 +1,132 @@
|
||||
#include "benchmark/benchmark.h"
|
||||
#include <nlohmann/json.hpp>
|
||||
#define BENCHPRESS_CONFIG_MAIN
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <benchpress.hpp>
|
||||
#include <json.hpp>
|
||||
#include <pthread.h>
|
||||
#include <thread>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// parse JSON from file
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void ParseFile(benchmark::State& state, const char* filename)
|
||||
struct StartUp
|
||||
{
|
||||
while (state.KeepRunning())
|
||||
StartUp()
|
||||
{
|
||||
state.PauseTiming();
|
||||
auto* f = new std::ifstream(filename);
|
||||
auto* j = new json();
|
||||
state.ResumeTiming();
|
||||
|
||||
*j = json::parse(*f);
|
||||
|
||||
state.PauseTiming();
|
||||
delete f;
|
||||
delete j;
|
||||
state.ResumeTiming();
|
||||
#ifndef __llvm__
|
||||
// pin thread to a single CPU
|
||||
cpu_set_t cpuset;
|
||||
pthread_t thread;
|
||||
thread = pthread_self();
|
||||
CPU_ZERO(&cpuset);
|
||||
CPU_SET(std::thread::hardware_concurrency() - 1, &cpuset);
|
||||
pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
StartUp startup;
|
||||
|
||||
std::ifstream file(filename, std::ios::binary | std::ios::ate);
|
||||
state.SetBytesProcessed(state.iterations() * file.tellg());
|
||||
}
|
||||
BENCHMARK_CAPTURE(ParseFile, jeopardy, "data/jeopardy/jeopardy.json");
|
||||
BENCHMARK_CAPTURE(ParseFile, canada, "data/nativejson-benchmark/canada.json");
|
||||
BENCHMARK_CAPTURE(ParseFile, citm_catalog, "data/nativejson-benchmark/citm_catalog.json");
|
||||
BENCHMARK_CAPTURE(ParseFile, twitter, "data/nativejson-benchmark/twitter.json");
|
||||
BENCHMARK_CAPTURE(ParseFile, floats, "data/numbers/floats.json");
|
||||
BENCHMARK_CAPTURE(ParseFile, signed_ints, "data/numbers/signed_ints.json");
|
||||
BENCHMARK_CAPTURE(ParseFile, unsigned_ints, "data/numbers/unsigned_ints.json");
|
||||
BENCHMARK_CAPTURE(ParseFile, small_signed_ints, "data/numbers/small_signed_ints.json");
|
||||
enum class EMode { input, output_no_indent, output_with_indent };
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// parse JSON from string
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void ParseString(benchmark::State& state, const char* filename)
|
||||
static void bench(benchpress::context& ctx,
|
||||
const std::string& in_path,
|
||||
const EMode mode)
|
||||
{
|
||||
std::ifstream f(filename);
|
||||
std::string str((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
|
||||
|
||||
while (state.KeepRunning())
|
||||
// using string streams for benchmarking to factor-out cold-cache disk
|
||||
// access.
|
||||
#if defined( FROMFILE )
|
||||
std::ifstream istr;
|
||||
{
|
||||
state.PauseTiming();
|
||||
auto* j = new json();
|
||||
state.ResumeTiming();
|
||||
istr.open( in_path, std::ifstream::in );
|
||||
|
||||
*j = json::parse(str);
|
||||
|
||||
state.PauseTiming();
|
||||
delete j;
|
||||
state.ResumeTiming();
|
||||
// read the stream once
|
||||
json j;
|
||||
istr >> j;
|
||||
// clear flags and rewind
|
||||
istr.clear();
|
||||
istr.seekg(0);
|
||||
}
|
||||
|
||||
state.SetBytesProcessed(state.iterations() * str.size());
|
||||
}
|
||||
BENCHMARK_CAPTURE(ParseString, jeopardy, "data/jeopardy/jeopardy.json");
|
||||
BENCHMARK_CAPTURE(ParseString, canada, "data/nativejson-benchmark/canada.json");
|
||||
BENCHMARK_CAPTURE(ParseString, citm_catalog, "data/nativejson-benchmark/citm_catalog.json");
|
||||
BENCHMARK_CAPTURE(ParseString, twitter, "data/nativejson-benchmark/twitter.json");
|
||||
BENCHMARK_CAPTURE(ParseString, floats, "data/numbers/floats.json");
|
||||
BENCHMARK_CAPTURE(ParseString, signed_ints, "data/numbers/signed_ints.json");
|
||||
BENCHMARK_CAPTURE(ParseString, unsigned_ints, "data/numbers/unsigned_ints.json");
|
||||
BENCHMARK_CAPTURE(ParseString, small_signed_ints, "data/numbers/small_signed_ints.json");
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// serialize JSON
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void Dump(benchmark::State& state, const char* filename, int indent)
|
||||
{
|
||||
std::ifstream f(filename);
|
||||
std::string str((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
|
||||
json j = json::parse(str);
|
||||
|
||||
while (state.KeepRunning())
|
||||
#else
|
||||
std::stringstream istr;
|
||||
{
|
||||
j.dump(indent);
|
||||
// read file into string stream
|
||||
std::ifstream input_file(in_path);
|
||||
istr << input_file.rdbuf();
|
||||
input_file.close();
|
||||
|
||||
// read the stream once
|
||||
json j;
|
||||
istr >> j;
|
||||
// clear flags and rewind
|
||||
istr.clear();
|
||||
istr.seekg(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
state.SetBytesProcessed(state.iterations() * j.dump(indent).size());
|
||||
switch (mode)
|
||||
{
|
||||
// benchmarking input
|
||||
case EMode::input:
|
||||
{
|
||||
ctx.reset_timer();
|
||||
|
||||
for (size_t i = 0; i < ctx.num_iterations(); ++i)
|
||||
{
|
||||
// clear flags and rewind
|
||||
istr.clear();
|
||||
istr.seekg(0);
|
||||
json j;
|
||||
istr >> j;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// benchmarking output
|
||||
case EMode::output_no_indent:
|
||||
case EMode::output_with_indent:
|
||||
{
|
||||
// create JSON value from input
|
||||
json j;
|
||||
istr >> j;
|
||||
std::stringstream ostr;
|
||||
|
||||
ctx.reset_timer();
|
||||
for (size_t i = 0; i < ctx.num_iterations(); ++i)
|
||||
{
|
||||
if (mode == EMode::output_no_indent)
|
||||
{
|
||||
ostr << j;
|
||||
}
|
||||
else
|
||||
{
|
||||
ostr << std::setw(4) << j;
|
||||
}
|
||||
|
||||
// reset data
|
||||
ostr.str(std::string());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
BENCHMARK_CAPTURE(Dump, jeopardy / -, "data/jeopardy/jeopardy.json", -1);
|
||||
BENCHMARK_CAPTURE(Dump, jeopardy / 4, "data/jeopardy/jeopardy.json", 4);
|
||||
BENCHMARK_CAPTURE(Dump, canada / -, "data/nativejson-benchmark/canada.json", -1);
|
||||
BENCHMARK_CAPTURE(Dump, canada / 4, "data/nativejson-benchmark/canada.json", 4);
|
||||
BENCHMARK_CAPTURE(Dump, citm_catalog / -, "data/nativejson-benchmark/citm_catalog.json", -1);
|
||||
BENCHMARK_CAPTURE(Dump, citm_catalog / 4, "data/nativejson-benchmark/citm_catalog.json", 4);
|
||||
BENCHMARK_CAPTURE(Dump, twitter / -, "data/nativejson-benchmark/twitter.json", -1);
|
||||
BENCHMARK_CAPTURE(Dump, twitter / 4, "data/nativejson-benchmark/twitter.json", 4);
|
||||
BENCHMARK_CAPTURE(Dump, floats / -, "data/numbers/floats.json", -1);
|
||||
BENCHMARK_CAPTURE(Dump, floats / 4, "data/numbers/floats.json", 4);
|
||||
BENCHMARK_CAPTURE(Dump, signed_ints / -, "data/numbers/signed_ints.json", -1);
|
||||
BENCHMARK_CAPTURE(Dump, signed_ints / 4, "data/numbers/signed_ints.json", 4);
|
||||
BENCHMARK_CAPTURE(Dump, unsigned_ints / -, "data/numbers/unsigned_ints.json", -1);
|
||||
BENCHMARK_CAPTURE(Dump, unsigned_ints / 4, "data/numbers/unsigned_ints.json", 4);
|
||||
BENCHMARK_CAPTURE(Dump, small_signed_ints / -, "data/numbers/small_signed_ints.json", -1);
|
||||
BENCHMARK_CAPTURE(Dump, small_signed_ints / 4, "data/numbers/small_signed_ints.json", 4);
|
||||
|
||||
#define BENCHMARK_I(mode, title, in_path) \
|
||||
BENCHMARK((title), [](benchpress::context* ctx) \
|
||||
{ \
|
||||
bench(*ctx, (in_path), (mode)); \
|
||||
})
|
||||
|
||||
BENCHMARK_MAIN();
|
||||
BENCHMARK_I(EMode::input, "parse jeopardy.json", "files/jeopardy/jeopardy.json");
|
||||
BENCHMARK_I(EMode::input, "parse canada.json", "files/nativejson-benchmark/canada.json");
|
||||
BENCHMARK_I(EMode::input, "parse citm_catalog.json", "files/nativejson-benchmark/citm_catalog.json");
|
||||
BENCHMARK_I(EMode::input, "parse twitter.json", "files/nativejson-benchmark/twitter.json");
|
||||
BENCHMARK_I(EMode::input, "parse numbers/floats.json", "files/numbers/floats.json");
|
||||
BENCHMARK_I(EMode::input, "parse numbers/signed_ints.json", "files/numbers/signed_ints.json");
|
||||
BENCHMARK_I(EMode::input, "parse numbers/unsigned_ints.json", "files/numbers/unsigned_ints.json");
|
||||
|
||||
BENCHMARK_I(EMode::output_no_indent, "dump jeopardy.json", "files/jeopardy/jeopardy.json");
|
||||
BENCHMARK_I(EMode::output_with_indent, "dump jeopardy.json with indent", "files/jeopardy/jeopardy.json");
|
||||
BENCHMARK_I(EMode::output_no_indent, "dump numbers/floats.json", "files/numbers/floats.json");
|
||||
BENCHMARK_I(EMode::output_no_indent, "dump numbers/signed_ints.json", "files/numbers/signed_ints.json");
|
||||
|
||||
158
benchmarks/src/benchmarks_simple.cpp
Normal file
158
benchmarks/src/benchmarks_simple.cpp
Normal file
@@ -0,0 +1,158 @@
|
||||
//
|
||||
// benchmarks_simple.cpp -- a less complex version of benchmarks.cpp, that better reflects actual performance
|
||||
//
|
||||
// For some reason, the complexity of benchmarks.cpp doesn't allow
|
||||
// the compiler to optimize code using json.hpp effectively. The
|
||||
// exact same tests, with the use of benchpress and cxxopts produces
|
||||
// much faster code, at least under g++.
|
||||
//
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <list>
|
||||
#include <tuple>
|
||||
|
||||
#include <json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
enum class EMode { input, output, indent };
|
||||
|
||||
static double bench(const EMode mode, size_t iters, const std::string& in_path )
|
||||
{
|
||||
// using string streams for benchmarking to factor-out cold-cache disk
|
||||
// access. Define FROMFILE to use file I/O instead.
|
||||
#if defined( FROMFILE )
|
||||
std::ifstream istr;
|
||||
{
|
||||
istr.open( in_path, std::ifstream::in );
|
||||
|
||||
// read the stream once
|
||||
json j;
|
||||
istr >> j;
|
||||
// clear flags and rewind
|
||||
istr.clear();
|
||||
istr.seekg(0);
|
||||
}
|
||||
#else
|
||||
std::stringstream istr;
|
||||
{
|
||||
// read file into string stream
|
||||
std::ifstream input_file(in_path);
|
||||
istr << input_file.rdbuf();
|
||||
input_file.close();
|
||||
|
||||
// read the stream once
|
||||
json j;
|
||||
istr >> j;
|
||||
// clear flags and rewind
|
||||
istr.clear();
|
||||
istr.seekg(0);
|
||||
}
|
||||
#endif
|
||||
double tps = 0;
|
||||
switch (mode)
|
||||
{
|
||||
// benchmarking input
|
||||
case EMode::input:
|
||||
{
|
||||
auto start = std::chrono::system_clock::now();
|
||||
for (size_t i = 0; i < iters; ++i)
|
||||
{
|
||||
// clear flags and rewind
|
||||
istr.clear();
|
||||
istr.seekg(0);
|
||||
json j;
|
||||
istr >> j;
|
||||
}
|
||||
auto ended = std::chrono::system_clock::now();
|
||||
tps = 1.0 / std::chrono::duration<double>( ended - start ).count();
|
||||
break;
|
||||
}
|
||||
|
||||
// benchmarking output
|
||||
case EMode::output:
|
||||
case EMode::indent:
|
||||
{
|
||||
// create JSON value from input
|
||||
json j;
|
||||
istr >> j;
|
||||
std::stringstream ostr;
|
||||
|
||||
auto start = std::chrono::system_clock::now();
|
||||
for (size_t i = 0; i < iters; ++i)
|
||||
{
|
||||
if (mode == EMode::indent)
|
||||
{
|
||||
ostr << j;
|
||||
}
|
||||
else
|
||||
{
|
||||
ostr << std::setw(4) << j;
|
||||
}
|
||||
|
||||
// reset data
|
||||
ostr.str(std::string());
|
||||
}
|
||||
auto ended = std::chrono::system_clock::now();
|
||||
tps = 1.0 / std::chrono::duration<double>( ended - start ).count();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
return tps;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct average {
|
||||
T _sum { 0 };
|
||||
size_t _count { 0 };
|
||||
T operator+=( const T &val_ ) { _sum += val_; +_count++; return val_; }
|
||||
operator T() { return _sum / _count; }
|
||||
};
|
||||
|
||||
// Execute each test approximately enough times to get near 1
|
||||
// transaction per second, and compute the average; a single aggregate
|
||||
// number that gives a performance metric representing both parsing
|
||||
// and output.
|
||||
|
||||
int main( int, char ** )
|
||||
{
|
||||
std::list<std::tuple<std::string, EMode, size_t, std::string>> tests {
|
||||
{ "parse jeopardy.json", EMode::input, 2, "files/jeopardy/jeopardy.json" },
|
||||
{ "parse canada.json", EMode::input, 30, "files/nativejson-benchmark/canada.json" },
|
||||
{ "parse citm_catalog.json", EMode::input, 120, "files/nativejson-benchmark/citm_catalog.json" },
|
||||
{ "parse twitter.json", EMode::input, 225, "files/nativejson-benchmark/twitter.json" },
|
||||
{ "parse floats.json", EMode::input, 5, "files/numbers/floats.json" },
|
||||
{ "parse signed_ints.json", EMode::input, 6, "files/numbers/signed_ints.json" },
|
||||
{ "parse unsigned_ints.json", EMode::input, 6, "files/numbers/unsigned_ints.json" },
|
||||
{ "dump jeopardy.json", EMode::output, 5, "files/jeopardy/jeopardy.json" },
|
||||
{ "dump jeopardy.json w/ind.", EMode::indent, 5, "files/jeopardy/jeopardy.json" },
|
||||
{ "dump floats.json", EMode::output, 2, "files/numbers/floats.json" },
|
||||
{ "dump signed_ints.json", EMode::output, 20, "files/numbers/signed_ints.json" },
|
||||
};
|
||||
|
||||
average<double> avg;
|
||||
for ( auto t : tests ) {
|
||||
std::string name, path;
|
||||
EMode mode;
|
||||
size_t iters;
|
||||
std::tie(name, mode, iters, path) = t;
|
||||
auto tps = bench( mode, iters, path );
|
||||
avg += tps;
|
||||
std::cout
|
||||
<< std::left
|
||||
<< std::setw( 30 ) << name
|
||||
<< std::right
|
||||
<< " x " << std::setw( 3 ) << iters
|
||||
<< std::left
|
||||
<< " == " << std::setw( 10 ) << tps
|
||||
<< std::right
|
||||
<< " TPS, " << std::setw( 8 ) << std::round( tps * 1e6 / iters )
|
||||
<< " ms/op"
|
||||
<< std::endl;
|
||||
}
|
||||
std::cout << std::setw( 40 ) << "" << std::string( 10, '-' ) << std::endl;
|
||||
std::cout << std::setw( 40 ) << "" << std::setw( 10 ) << std::left << avg << " TPS Average" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
46
benchmarks/thirdparty/benchmark/AUTHORS
vendored
46
benchmarks/thirdparty/benchmark/AUTHORS
vendored
@@ -1,46 +0,0 @@
|
||||
# This is the official list of benchmark authors for copyright purposes.
|
||||
# This file is distinct from the CONTRIBUTORS files.
|
||||
# See the latter for an explanation.
|
||||
#
|
||||
# Names should be added to this file as:
|
||||
# Name or Organization <email address>
|
||||
# The email address is not required for organizations.
|
||||
#
|
||||
# Please keep the list sorted.
|
||||
|
||||
Albert Pretorius <pretoalb@gmail.com>
|
||||
Arne Beer <arne@twobeer.de>
|
||||
Carto
|
||||
Christopher Seymour <chris.j.seymour@hotmail.com>
|
||||
David Coeurjolly <david.coeurjolly@liris.cnrs.fr>
|
||||
Deniz Evrenci <denizevrenci@gmail.com>
|
||||
Dirac Research
|
||||
Dominik Czarnota <dominik.b.czarnota@gmail.com>
|
||||
Eric Fiselier <eric@efcs.ca>
|
||||
Eugene Zhuk <eugene.zhuk@gmail.com>
|
||||
Evgeny Safronov <division494@gmail.com>
|
||||
Felix Homann <linuxaudio@showlabor.de>
|
||||
Google Inc.
|
||||
International Business Machines Corporation
|
||||
Ismael Jimenez Martinez <ismael.jimenez.martinez@gmail.com>
|
||||
Jern-Kuan Leong <jernkuan@gmail.com>
|
||||
JianXiong Zhou <zhoujianxiong2@gmail.com>
|
||||
Joao Paulo Magalhaes <joaoppmagalhaes@gmail.com>
|
||||
Jussi Knuuttila <jussi.knuuttila@gmail.com>
|
||||
Kaito Udagawa <umireon@gmail.com>
|
||||
Kishan Kumar <kumar.kishan@outlook.com>
|
||||
Lei Xu <eddyxu@gmail.com>
|
||||
Matt Clarkson <mattyclarkson@gmail.com>
|
||||
Maxim Vafin <maxvafin@gmail.com>
|
||||
MongoDB Inc.
|
||||
Nick Hutchinson <nshutchinson@gmail.com>
|
||||
Oleksandr Sochka <sasha.sochka@gmail.com>
|
||||
Paul Redmond <paul.redmond@gmail.com>
|
||||
Radoslav Yovchev <radoslav.tm@gmail.com>
|
||||
Roman Lebedev <lebedev.ri@gmail.com>
|
||||
Shuo Chen <chenshuo@chenshuo.com>
|
||||
Steinar H. Gunderson <sgunderson@bigfoot.com>
|
||||
Stripe, Inc.
|
||||
Yixuan Qiu <yixuanq@gmail.com>
|
||||
Yusuke Suzuki <utatane.tea@gmail.com>
|
||||
Zbigniew Skowron <zbychs@gmail.com>
|
||||
42
benchmarks/thirdparty/benchmark/BUILD.bazel
vendored
42
benchmarks/thirdparty/benchmark/BUILD.bazel
vendored
@@ -1,42 +0,0 @@
|
||||
licenses(["notice"])
|
||||
|
||||
config_setting(
|
||||
name = "windows",
|
||||
values = {
|
||||
"cpu": "x64_windows",
|
||||
},
|
||||
visibility = [":__subpackages__"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "benchmark",
|
||||
srcs = glob(
|
||||
[
|
||||
"src/*.cc",
|
||||
"src/*.h",
|
||||
],
|
||||
exclude = ["src/benchmark_main.cc"],
|
||||
),
|
||||
hdrs = ["include/benchmark/benchmark.h"],
|
||||
linkopts = select({
|
||||
":windows": ["-DEFAULTLIB:shlwapi.lib"],
|
||||
"//conditions:default": ["-pthread"],
|
||||
}),
|
||||
strip_include_prefix = "include",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "benchmark_main",
|
||||
srcs = ["src/benchmark_main.cc"],
|
||||
hdrs = ["include/benchmark/benchmark.h"],
|
||||
strip_include_prefix = "include",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [":benchmark"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "benchmark_internal_headers",
|
||||
hdrs = glob(["src/*.h"]),
|
||||
visibility = ["//test:__pkg__"],
|
||||
)
|
||||
251
benchmarks/thirdparty/benchmark/CMakeLists.txt
vendored
251
benchmarks/thirdparty/benchmark/CMakeLists.txt
vendored
@@ -1,251 +0,0 @@
|
||||
cmake_minimum_required (VERSION 2.8.12)
|
||||
|
||||
project (benchmark)
|
||||
|
||||
foreach(p
|
||||
CMP0054 # CMake 3.1
|
||||
CMP0056 # export EXE_LINKER_FLAGS to try_run
|
||||
CMP0057 # Support no if() IN_LIST operator
|
||||
)
|
||||
if(POLICY ${p})
|
||||
cmake_policy(SET ${p} NEW)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
option(BENCHMARK_ENABLE_TESTING "Enable testing of the benchmark library." ON)
|
||||
option(BENCHMARK_ENABLE_EXCEPTIONS "Enable the use of exceptions in the benchmark library." ON)
|
||||
option(BENCHMARK_ENABLE_LTO "Enable link time optimisation of the benchmark library." OFF)
|
||||
option(BENCHMARK_USE_LIBCXX "Build and test using libc++ as the standard library." OFF)
|
||||
option(BENCHMARK_BUILD_32_BITS "Build a 32 bit version of the library." OFF)
|
||||
option(BENCHMARK_ENABLE_INSTALL "Enable installation of benchmark. (Projects embedding benchmark may want to turn this OFF.)" ON)
|
||||
|
||||
# Allow unmet dependencies to be met using CMake's ExternalProject mechanics, which
|
||||
# may require downloading the source code.
|
||||
option(BENCHMARK_DOWNLOAD_DEPENDENCIES "Allow the downloading and in-tree building of unmet dependencies" OFF)
|
||||
|
||||
# This option can be used to disable building and running unit tests which depend on gtest
|
||||
# in cases where it is not possible to build or find a valid version of gtest.
|
||||
option(BENCHMARK_ENABLE_GTEST_TESTS "Enable building the unit tests which depend on gtest" ON)
|
||||
|
||||
set(ENABLE_ASSEMBLY_TESTS_DEFAULT OFF)
|
||||
function(should_enable_assembly_tests)
|
||||
if(CMAKE_BUILD_TYPE)
|
||||
string(TOLOWER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_LOWER)
|
||||
if (${CMAKE_BUILD_TYPE_LOWER} MATCHES "coverage")
|
||||
# FIXME: The --coverage flag needs to be removed when building assembly
|
||||
# tests for this to work.
|
||||
return()
|
||||
endif()
|
||||
endif()
|
||||
if (MSVC)
|
||||
return()
|
||||
elseif(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
|
||||
return()
|
||||
elseif(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
# FIXME: Make these work on 32 bit builds
|
||||
return()
|
||||
elseif(BENCHMARK_BUILD_32_BITS)
|
||||
# FIXME: Make these work on 32 bit builds
|
||||
return()
|
||||
endif()
|
||||
find_program(LLVM_FILECHECK_EXE FileCheck)
|
||||
if (LLVM_FILECHECK_EXE)
|
||||
set(LLVM_FILECHECK_EXE "${LLVM_FILECHECK_EXE}" CACHE PATH "llvm filecheck" FORCE)
|
||||
message(STATUS "LLVM FileCheck Found: ${LLVM_FILECHECK_EXE}")
|
||||
else()
|
||||
message(STATUS "Failed to find LLVM FileCheck")
|
||||
return()
|
||||
endif()
|
||||
set(ENABLE_ASSEMBLY_TESTS_DEFAULT ON PARENT_SCOPE)
|
||||
endfunction()
|
||||
should_enable_assembly_tests()
|
||||
|
||||
# This option disables the building and running of the assembly verification tests
|
||||
option(BENCHMARK_ENABLE_ASSEMBLY_TESTS "Enable building and running the assembly tests"
|
||||
${ENABLE_ASSEMBLY_TESTS_DEFAULT})
|
||||
|
||||
# Make sure we can import out CMake functions
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules")
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
|
||||
|
||||
# Read the git tags to determine the project version
|
||||
include(GetGitVersion)
|
||||
get_git_version(GIT_VERSION)
|
||||
|
||||
# Tell the user what versions we are using
|
||||
string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" VERSION ${GIT_VERSION})
|
||||
message("-- Version: ${VERSION}")
|
||||
|
||||
# The version of the libraries
|
||||
set(GENERIC_LIB_VERSION ${VERSION})
|
||||
string(SUBSTRING ${VERSION} 0 1 GENERIC_LIB_SOVERSION)
|
||||
|
||||
# Import our CMake modules
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(AddCXXCompilerFlag)
|
||||
include(CXXFeatureCheck)
|
||||
|
||||
if (BENCHMARK_BUILD_32_BITS)
|
||||
add_required_cxx_compiler_flag(-m32)
|
||||
endif()
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
# Turn compiler warnings up to 11
|
||||
string(REGEX REPLACE "[-/]W[1-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
|
||||
if (NOT BENCHMARK_ENABLE_EXCEPTIONS)
|
||||
add_cxx_compiler_flag(-EHs-)
|
||||
add_cxx_compiler_flag(-EHa-)
|
||||
endif()
|
||||
# Link time optimisation
|
||||
if (BENCHMARK_ENABLE_LTO)
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL")
|
||||
set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /GL")
|
||||
string(REGEX REPLACE "[-/]INCREMENTAL" "/INCREMENTAL:NO" CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO}")
|
||||
set(CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO} /LTCG")
|
||||
string(REGEX REPLACE "[-/]INCREMENTAL" "/INCREMENTAL:NO" CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} /LTCG")
|
||||
string(REGEX REPLACE "[-/]INCREMENTAL" "/INCREMENTAL:NO" CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} /LTCG")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /GL")
|
||||
set(CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL "${CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL} /LTCG")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL "${CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL} /LTCG")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL} /LTCG")
|
||||
endif()
|
||||
else()
|
||||
# Try and enable C++11. Don't use C++14 because it doesn't work in some
|
||||
# configurations.
|
||||
add_cxx_compiler_flag(-std=c++11)
|
||||
if (NOT HAVE_CXX_FLAG_STD_CXX11)
|
||||
add_cxx_compiler_flag(-std=c++0x)
|
||||
endif()
|
||||
|
||||
# Turn compiler warnings up to 11
|
||||
add_cxx_compiler_flag(-Wall)
|
||||
|
||||
add_cxx_compiler_flag(-Wextra)
|
||||
add_cxx_compiler_flag(-Wshadow)
|
||||
add_cxx_compiler_flag(-Werror RELEASE)
|
||||
add_cxx_compiler_flag(-Werror RELWITHDEBINFO)
|
||||
add_cxx_compiler_flag(-Werror MINSIZEREL)
|
||||
add_cxx_compiler_flag(-pedantic)
|
||||
add_cxx_compiler_flag(-pedantic-errors)
|
||||
add_cxx_compiler_flag(-Wshorten-64-to-32)
|
||||
add_cxx_compiler_flag(-Wfloat-equal)
|
||||
add_cxx_compiler_flag(-fstrict-aliasing)
|
||||
if (NOT BENCHMARK_ENABLE_EXCEPTIONS)
|
||||
add_cxx_compiler_flag(-fno-exceptions)
|
||||
endif()
|
||||
|
||||
if (HAVE_CXX_FLAG_FSTRICT_ALIASING)
|
||||
if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Intel") #ICC17u2: Many false positives for Wstrict-aliasing
|
||||
add_cxx_compiler_flag(-Wstrict-aliasing)
|
||||
endif()
|
||||
endif()
|
||||
# ICC17u2: overloaded virtual function "benchmark::Fixture::SetUp" is only partially overridden
|
||||
# (because of deprecated overload)
|
||||
add_cxx_compiler_flag(-wd654)
|
||||
add_cxx_compiler_flag(-Wthread-safety)
|
||||
if (HAVE_CXX_FLAG_WTHREAD_SAFETY)
|
||||
cxx_feature_check(THREAD_SAFETY_ATTRIBUTES)
|
||||
endif()
|
||||
|
||||
# On most UNIX like platforms g++ and clang++ define _GNU_SOURCE as a
|
||||
# predefined macro, which turns on all of the wonderful libc extensions.
|
||||
# However g++ doesn't do this in Cygwin so we have to define it ourselfs
|
||||
# since we depend on GNU/POSIX/BSD extensions.
|
||||
if (CYGWIN)
|
||||
add_definitions(-D_GNU_SOURCE=1)
|
||||
endif()
|
||||
|
||||
# Link time optimisation
|
||||
if (BENCHMARK_ENABLE_LTO)
|
||||
add_cxx_compiler_flag(-flto)
|
||||
if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
|
||||
find_program(GCC_AR gcc-ar)
|
||||
if (GCC_AR)
|
||||
set(CMAKE_AR ${GCC_AR})
|
||||
endif()
|
||||
find_program(GCC_RANLIB gcc-ranlib)
|
||||
if (GCC_RANLIB)
|
||||
set(CMAKE_RANLIB ${GCC_RANLIB})
|
||||
endif()
|
||||
elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
|
||||
include(llvm-toolchain)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Coverage build type
|
||||
set(BENCHMARK_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_DEBUG}"
|
||||
CACHE STRING "Flags used by the C++ compiler during coverage builds."
|
||||
FORCE)
|
||||
set(BENCHMARK_EXE_LINKER_FLAGS_COVERAGE "${CMAKE_EXE_LINKER_FLAGS_DEBUG}"
|
||||
CACHE STRING "Flags used for linking binaries during coverage builds."
|
||||
FORCE)
|
||||
set(BENCHMARK_SHARED_LINKER_FLAGS_COVERAGE "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}"
|
||||
CACHE STRING "Flags used by the shared libraries linker during coverage builds."
|
||||
FORCE)
|
||||
mark_as_advanced(
|
||||
BENCHMARK_CXX_FLAGS_COVERAGE
|
||||
BENCHMARK_EXE_LINKER_FLAGS_COVERAGE
|
||||
BENCHMARK_SHARED_LINKER_FLAGS_COVERAGE)
|
||||
set(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING
|
||||
"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel Coverage.")
|
||||
add_cxx_compiler_flag(--coverage COVERAGE)
|
||||
endif()
|
||||
|
||||
if (BENCHMARK_USE_LIBCXX)
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
add_cxx_compiler_flag(-stdlib=libc++)
|
||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR
|
||||
"${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
|
||||
add_cxx_compiler_flag(-nostdinc++)
|
||||
message("libc++ header path must be manually specified using CMAKE_CXX_FLAGS")
|
||||
# Adding -nodefaultlibs directly to CMAKE_<TYPE>_LINKER_FLAGS will break
|
||||
# configuration checks such as 'find_package(Threads)'
|
||||
list(APPEND BENCHMARK_CXX_LINKER_FLAGS -nodefaultlibs)
|
||||
# -lc++ cannot be added directly to CMAKE_<TYPE>_LINKER_FLAGS because
|
||||
# linker flags appear before all linker inputs and -lc++ must appear after.
|
||||
list(APPEND BENCHMARK_CXX_LIBRARIES c++)
|
||||
else()
|
||||
message(FATAL_ERROR "-DBENCHMARK_USE_LIBCXX:BOOL=ON is not supported for compiler")
|
||||
endif()
|
||||
endif(BENCHMARK_USE_LIBCXX)
|
||||
|
||||
# C++ feature checks
|
||||
# Determine the correct regular expression engine to use
|
||||
cxx_feature_check(STD_REGEX)
|
||||
cxx_feature_check(GNU_POSIX_REGEX)
|
||||
cxx_feature_check(POSIX_REGEX)
|
||||
if(NOT HAVE_STD_REGEX AND NOT HAVE_GNU_POSIX_REGEX AND NOT HAVE_POSIX_REGEX)
|
||||
message(FATAL_ERROR "Failed to determine the source files for the regular expression backend")
|
||||
endif()
|
||||
if (NOT BENCHMARK_ENABLE_EXCEPTIONS AND HAVE_STD_REGEX
|
||||
AND NOT HAVE_GNU_POSIX_REGEX AND NOT HAVE_POSIX_REGEX)
|
||||
message(WARNING "Using std::regex with exceptions disabled is not fully supported")
|
||||
endif()
|
||||
cxx_feature_check(STEADY_CLOCK)
|
||||
# Ensure we have pthreads
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
# Set up directories
|
||||
include_directories(${PROJECT_SOURCE_DIR}/include)
|
||||
|
||||
# Build the targets
|
||||
add_subdirectory(src)
|
||||
|
||||
if (BENCHMARK_ENABLE_TESTING)
|
||||
enable_testing()
|
||||
if (BENCHMARK_ENABLE_GTEST_TESTS)
|
||||
include(HandleGTest)
|
||||
endif()
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
58
benchmarks/thirdparty/benchmark/CONTRIBUTING.md
vendored
58
benchmarks/thirdparty/benchmark/CONTRIBUTING.md
vendored
@@ -1,58 +0,0 @@
|
||||
# How to contribute #
|
||||
|
||||
We'd love to accept your patches and contributions to this project. There are
|
||||
a just a few small guidelines you need to follow.
|
||||
|
||||
|
||||
## Contributor License Agreement ##
|
||||
|
||||
Contributions to any Google project must be accompanied by a Contributor
|
||||
License Agreement. This is not a copyright **assignment**, it simply gives
|
||||
Google permission to use and redistribute your contributions as part of the
|
||||
project.
|
||||
|
||||
* If you are an individual writing original source code and you're sure you
|
||||
own the intellectual property, then you'll need to sign an [individual
|
||||
CLA][].
|
||||
|
||||
* If you work for a company that wants to allow you to contribute your work,
|
||||
then you'll need to sign a [corporate CLA][].
|
||||
|
||||
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.
|
||||
|
||||
[individual CLA]: https://developers.google.com/open-source/cla/individual
|
||||
[corporate CLA]: https://developers.google.com/open-source/cla/corporate
|
||||
|
||||
Once your CLA is submitted (or if you already submitted one for
|
||||
another Google project), make a commit adding yourself to the
|
||||
[AUTHORS][] and [CONTRIBUTORS][] files. This commit can be part
|
||||
of your first [pull request][].
|
||||
|
||||
[AUTHORS]: AUTHORS
|
||||
[CONTRIBUTORS]: CONTRIBUTORS
|
||||
|
||||
|
||||
## Submitting a patch ##
|
||||
|
||||
1. It's generally best to start by opening a new issue describing the bug or
|
||||
feature you're intending to fix. Even if you think it's relatively minor,
|
||||
it's helpful to know what people are working on. Mention in the initial
|
||||
issue that you are planning to work on that bug or feature so that it can
|
||||
be assigned to you.
|
||||
|
||||
1. Follow the normal process of [forking][] the project, and setup a new
|
||||
branch to work in. It's important that each group of changes be done in
|
||||
separate branches in order to ensure that a pull request only includes the
|
||||
commits related to that bug or feature.
|
||||
|
||||
1. Do your best to have [well-formed commit messages][] for each change.
|
||||
This provides consistency throughout the project, and ensures that commit
|
||||
messages are able to be formatted properly by various git tools.
|
||||
|
||||
1. Finally, push the commits to your fork and submit a [pull request][].
|
||||
|
||||
[forking]: https://help.github.com/articles/fork-a-repo
|
||||
[well-formed commit messages]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
|
||||
[pull request]: https://help.github.com/articles/creating-a-pull-request
|
||||
65
benchmarks/thirdparty/benchmark/CONTRIBUTORS
vendored
65
benchmarks/thirdparty/benchmark/CONTRIBUTORS
vendored
@@ -1,65 +0,0 @@
|
||||
# People who have agreed to one of the CLAs and can contribute patches.
|
||||
# The AUTHORS file lists the copyright holders; this file
|
||||
# lists people. For example, Google employees are listed here
|
||||
# but not in AUTHORS, because Google holds the copyright.
|
||||
#
|
||||
# Names should be added to this file only after verifying that
|
||||
# the individual or the individual's organization has agreed to
|
||||
# the appropriate Contributor License Agreement, found here:
|
||||
#
|
||||
# https://developers.google.com/open-source/cla/individual
|
||||
# https://developers.google.com/open-source/cla/corporate
|
||||
#
|
||||
# The agreement for individuals can be filled out on the web.
|
||||
#
|
||||
# When adding J Random Contributor's name to this file,
|
||||
# either J's name or J's organization's name should be
|
||||
# added to the AUTHORS file, depending on whether the
|
||||
# individual or corporate CLA was used.
|
||||
#
|
||||
# Names should be added to this file as:
|
||||
# Name <email address>
|
||||
#
|
||||
# Please keep the list sorted.
|
||||
|
||||
Albert Pretorius <pretoalb@gmail.com>
|
||||
Arne Beer <arne@twobeer.de>
|
||||
Billy Robert O'Neal III <billy.oneal@gmail.com> <bion@microsoft.com>
|
||||
Chris Kennelly <ckennelly@google.com> <ckennelly@ckennelly.com>
|
||||
Christopher Seymour <chris.j.seymour@hotmail.com>
|
||||
David Coeurjolly <david.coeurjolly@liris.cnrs.fr>
|
||||
Deniz Evrenci <denizevrenci@gmail.com>
|
||||
Dominic Hamon <dma@stripysock.com> <dominic@google.com>
|
||||
Dominik Czarnota <dominik.b.czarnota@gmail.com>
|
||||
Eric Fiselier <eric@efcs.ca>
|
||||
Eugene Zhuk <eugene.zhuk@gmail.com>
|
||||
Evgeny Safronov <division494@gmail.com>
|
||||
Felix Homann <linuxaudio@showlabor.de>
|
||||
Ismael Jimenez Martinez <ismael.jimenez.martinez@gmail.com>
|
||||
Jern-Kuan Leong <jernkuan@gmail.com>
|
||||
JianXiong Zhou <zhoujianxiong2@gmail.com>
|
||||
Joao Paulo Magalhaes <joaoppmagalhaes@gmail.com>
|
||||
John Millikin <jmillikin@stripe.com>
|
||||
Jussi Knuuttila <jussi.knuuttila@gmail.com>
|
||||
Kai Wolf <kai.wolf@gmail.com>
|
||||
Kishan Kumar <kumar.kishan@outlook.com>
|
||||
Kaito Udagawa <umireon@gmail.com>
|
||||
Lei Xu <eddyxu@gmail.com>
|
||||
Matt Clarkson <mattyclarkson@gmail.com>
|
||||
Maxim Vafin <maxvafin@gmail.com>
|
||||
Nick Hutchinson <nshutchinson@gmail.com>
|
||||
Oleksandr Sochka <sasha.sochka@gmail.com>
|
||||
Pascal Leroy <phl@google.com>
|
||||
Paul Redmond <paul.redmond@gmail.com>
|
||||
Pierre Phaneuf <pphaneuf@google.com>
|
||||
Radoslav Yovchev <radoslav.tm@gmail.com>
|
||||
Raul Marin <rmrodriguez@cartodb.com>
|
||||
Ray Glover <ray.glover@uk.ibm.com>
|
||||
Robert Guo <robert.guo@mongodb.com>
|
||||
Roman Lebedev <lebedev.ri@gmail.com>
|
||||
Shuo Chen <chenshuo@chenshuo.com>
|
||||
Tobias Ulvgård <tobias.ulvgard@dirac.se>
|
||||
Tom Madams <tom.ej.madams@gmail.com> <tmadams@google.com>
|
||||
Yixuan Qiu <yixuanq@gmail.com>
|
||||
Yusuke Suzuki <utatane.tea@gmail.com>
|
||||
Zbigniew Skowron <zbychs@gmail.com>
|
||||
202
benchmarks/thirdparty/benchmark/LICENSE
vendored
202
benchmarks/thirdparty/benchmark/LICENSE
vendored
@@ -1,202 +0,0 @@
|
||||
|
||||
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.
|
||||
950
benchmarks/thirdparty/benchmark/README.md
vendored
950
benchmarks/thirdparty/benchmark/README.md
vendored
@@ -1,950 +0,0 @@
|
||||
# benchmark
|
||||
[](https://travis-ci.org/google/benchmark)
|
||||
[](https://ci.appveyor.com/project/google/benchmark/branch/master)
|
||||
[](https://coveralls.io/r/google/benchmark)
|
||||
[](https://slackin-iqtfqnpzxd.now.sh/)
|
||||
|
||||
A library to support the benchmarking of functions, similar to unit-tests.
|
||||
|
||||
Discussion group: https://groups.google.com/d/forum/benchmark-discuss
|
||||
|
||||
IRC channel: https://freenode.net #googlebenchmark
|
||||
|
||||
[Known issues and common problems](#known-issues)
|
||||
|
||||
[Additional Tooling Documentation](docs/tools.md)
|
||||
|
||||
[Assembly Testing Documentation](docs/AssemblyTests.md)
|
||||
|
||||
|
||||
## Building
|
||||
|
||||
The basic steps for configuring and building the library look like this:
|
||||
|
||||
```bash
|
||||
$ git clone https://github.com/google/benchmark.git
|
||||
# Benchmark requires Google Test as a dependency. Add the source tree as a subdirectory.
|
||||
$ git clone https://github.com/google/googletest.git benchmark/googletest
|
||||
$ mkdir build && cd build
|
||||
$ cmake -G <generator> [options] ../benchmark
|
||||
# Assuming a makefile generator was used
|
||||
$ make
|
||||
```
|
||||
|
||||
Note that Google Benchmark requires Google Test to build and run the tests. This
|
||||
dependency can be provided two ways:
|
||||
|
||||
* Checkout the Google Test sources into `benchmark/googletest` as above.
|
||||
* Otherwise, if `-DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON` is specified during
|
||||
configuration, the library will automatically download and build any required
|
||||
dependencies.
|
||||
|
||||
If you do not wish to build and run the tests, add `-DBENCHMARK_ENABLE_GTEST_TESTS=OFF`
|
||||
to `CMAKE_ARGS`.
|
||||
|
||||
|
||||
## Installation Guide
|
||||
|
||||
For Ubuntu and Debian Based System
|
||||
|
||||
First make sure you have git and cmake installed (If not please install it)
|
||||
|
||||
```
|
||||
sudo apt-get install git
|
||||
sudo apt-get install cmake
|
||||
```
|
||||
|
||||
Now, let's clone the repository and build it
|
||||
|
||||
```
|
||||
git clone https://github.com/google/benchmark.git
|
||||
cd benchmark
|
||||
git clone https://github.com/google/googletest.git
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_BUILD_TYPE=RELEASE
|
||||
make
|
||||
```
|
||||
|
||||
We need to install the library globally now
|
||||
|
||||
```
|
||||
sudo make install
|
||||
```
|
||||
|
||||
Now you have google/benchmark installed in your machine
|
||||
Note: Don't forget to link to pthread library while building
|
||||
|
||||
## Stable and Experimental Library Versions
|
||||
|
||||
The main branch contains the latest stable version of the benchmarking library;
|
||||
the API of which can be considered largely stable, with source breaking changes
|
||||
being made only upon the release of a new major version.
|
||||
|
||||
Newer, experimental, features are implemented and tested on the
|
||||
[`v2` branch](https://github.com/google/benchmark/tree/v2). Users who wish
|
||||
to use, test, and provide feedback on the new features are encouraged to try
|
||||
this branch. However, this branch provides no stability guarantees and reserves
|
||||
the right to change and break the API at any time.
|
||||
|
||||
##Prerequisite knowledge
|
||||
|
||||
Before attempting to understand this framework one should ideally have some familiarity with the structure and format of the Google Test framework, upon which it is based. Documentation for Google Test, including a "Getting Started" (primer) guide, is available here:
|
||||
https://github.com/google/googletest/blob/master/googletest/docs/Documentation.md
|
||||
|
||||
|
||||
## Example usage
|
||||
### Basic usage
|
||||
Define a function that executes the code to be measured.
|
||||
|
||||
```c++
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
static void BM_StringCreation(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
std::string empty_string;
|
||||
}
|
||||
// Register the function as a benchmark
|
||||
BENCHMARK(BM_StringCreation);
|
||||
|
||||
// Define another benchmark
|
||||
static void BM_StringCopy(benchmark::State& state) {
|
||||
std::string x = "hello";
|
||||
for (auto _ : state)
|
||||
std::string copy(x);
|
||||
}
|
||||
BENCHMARK(BM_StringCopy);
|
||||
|
||||
BENCHMARK_MAIN();
|
||||
```
|
||||
|
||||
Don't forget to inform your linker to add benchmark library e.g. through
|
||||
`-lbenchmark` compilation flag. Alternatively, you may leave out the
|
||||
`BENCHMARK_MAIN();` at the end of the source file and link against
|
||||
`-lbenchmark_main` to get the same default behavior.
|
||||
|
||||
The benchmark library will reporting the timing for the code within the `for(...)` loop.
|
||||
|
||||
### Passing arguments
|
||||
Sometimes a family of benchmarks can be implemented with just one routine that
|
||||
takes an extra argument to specify which one of the family of benchmarks to
|
||||
run. For example, the following code defines a family of benchmarks for
|
||||
measuring the speed of `memcpy()` calls of different lengths:
|
||||
|
||||
```c++
|
||||
static void BM_memcpy(benchmark::State& state) {
|
||||
char* src = new char[state.range(0)];
|
||||
char* dst = new char[state.range(0)];
|
||||
memset(src, 'x', state.range(0));
|
||||
for (auto _ : state)
|
||||
memcpy(dst, src, state.range(0));
|
||||
state.SetBytesProcessed(int64_t(state.iterations()) *
|
||||
int64_t(state.range(0)));
|
||||
delete[] src;
|
||||
delete[] dst;
|
||||
}
|
||||
BENCHMARK(BM_memcpy)->Arg(8)->Arg(64)->Arg(512)->Arg(1<<10)->Arg(8<<10);
|
||||
```
|
||||
|
||||
The preceding code is quite repetitive, and can be replaced with the following
|
||||
short-hand. The following invocation will pick a few appropriate arguments in
|
||||
the specified range and will generate a benchmark for each such argument.
|
||||
|
||||
```c++
|
||||
BENCHMARK(BM_memcpy)->Range(8, 8<<10);
|
||||
```
|
||||
|
||||
By default the arguments in the range are generated in multiples of eight and
|
||||
the command above selects [ 8, 64, 512, 4k, 8k ]. In the following code the
|
||||
range multiplier is changed to multiples of two.
|
||||
|
||||
```c++
|
||||
BENCHMARK(BM_memcpy)->RangeMultiplier(2)->Range(8, 8<<10);
|
||||
```
|
||||
Now arguments generated are [ 8, 16, 32, 64, 128, 256, 512, 1024, 2k, 4k, 8k ].
|
||||
|
||||
You might have a benchmark that depends on two or more inputs. For example, the
|
||||
following code defines a family of benchmarks for measuring the speed of set
|
||||
insertion.
|
||||
|
||||
```c++
|
||||
static void BM_SetInsert(benchmark::State& state) {
|
||||
std::set<int> data;
|
||||
for (auto _ : state) {
|
||||
state.PauseTiming();
|
||||
data = ConstructRandomSet(state.range(0));
|
||||
state.ResumeTiming();
|
||||
for (int j = 0; j < state.range(1); ++j)
|
||||
data.insert(RandomNumber());
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_SetInsert)
|
||||
->Args({1<<10, 128})
|
||||
->Args({2<<10, 128})
|
||||
->Args({4<<10, 128})
|
||||
->Args({8<<10, 128})
|
||||
->Args({1<<10, 512})
|
||||
->Args({2<<10, 512})
|
||||
->Args({4<<10, 512})
|
||||
->Args({8<<10, 512});
|
||||
```
|
||||
|
||||
The preceding code is quite repetitive, and can be replaced with the following
|
||||
short-hand. The following macro will pick a few appropriate arguments in the
|
||||
product of the two specified ranges and will generate a benchmark for each such
|
||||
pair.
|
||||
|
||||
```c++
|
||||
BENCHMARK(BM_SetInsert)->Ranges({{1<<10, 8<<10}, {128, 512}});
|
||||
```
|
||||
|
||||
For more complex patterns of inputs, passing a custom function to `Apply` allows
|
||||
programmatic specification of an arbitrary set of arguments on which to run the
|
||||
benchmark. The following example enumerates a dense range on one parameter,
|
||||
and a sparse range on the second.
|
||||
|
||||
```c++
|
||||
static void CustomArguments(benchmark::internal::Benchmark* b) {
|
||||
for (int i = 0; i <= 10; ++i)
|
||||
for (int j = 32; j <= 1024*1024; j *= 8)
|
||||
b->Args({i, j});
|
||||
}
|
||||
BENCHMARK(BM_SetInsert)->Apply(CustomArguments);
|
||||
```
|
||||
|
||||
### Calculate asymptotic complexity (Big O)
|
||||
Asymptotic complexity might be calculated for a family of benchmarks. The
|
||||
following code will calculate the coefficient for the high-order term in the
|
||||
running time and the normalized root-mean square error of string comparison.
|
||||
|
||||
```c++
|
||||
static void BM_StringCompare(benchmark::State& state) {
|
||||
std::string s1(state.range(0), '-');
|
||||
std::string s2(state.range(0), '-');
|
||||
for (auto _ : state) {
|
||||
benchmark::DoNotOptimize(s1.compare(s2));
|
||||
}
|
||||
state.SetComplexityN(state.range(0));
|
||||
}
|
||||
BENCHMARK(BM_StringCompare)
|
||||
->RangeMultiplier(2)->Range(1<<10, 1<<18)->Complexity(benchmark::oN);
|
||||
```
|
||||
|
||||
As shown in the following invocation, asymptotic complexity might also be
|
||||
calculated automatically.
|
||||
|
||||
```c++
|
||||
BENCHMARK(BM_StringCompare)
|
||||
->RangeMultiplier(2)->Range(1<<10, 1<<18)->Complexity();
|
||||
```
|
||||
|
||||
The following code will specify asymptotic complexity with a lambda function,
|
||||
that might be used to customize high-order term calculation.
|
||||
|
||||
```c++
|
||||
BENCHMARK(BM_StringCompare)->RangeMultiplier(2)
|
||||
->Range(1<<10, 1<<18)->Complexity([](int n)->double{return n; });
|
||||
```
|
||||
|
||||
### Templated benchmarks
|
||||
Templated benchmarks work the same way: This example produces and consumes
|
||||
messages of size `sizeof(v)` `range_x` times. It also outputs throughput in the
|
||||
absence of multiprogramming.
|
||||
|
||||
```c++
|
||||
template <class Q> int BM_Sequential(benchmark::State& state) {
|
||||
Q q;
|
||||
typename Q::value_type v;
|
||||
for (auto _ : state) {
|
||||
for (int i = state.range(0); i--; )
|
||||
q.push(v);
|
||||
for (int e = state.range(0); e--; )
|
||||
q.Wait(&v);
|
||||
}
|
||||
// actually messages, not bytes:
|
||||
state.SetBytesProcessed(
|
||||
static_cast<int64_t>(state.iterations())*state.range(0));
|
||||
}
|
||||
BENCHMARK_TEMPLATE(BM_Sequential, WaitQueue<int>)->Range(1<<0, 1<<10);
|
||||
```
|
||||
|
||||
Three macros are provided for adding benchmark templates.
|
||||
|
||||
```c++
|
||||
#ifdef BENCHMARK_HAS_CXX11
|
||||
#define BENCHMARK_TEMPLATE(func, ...) // Takes any number of parameters.
|
||||
#else // C++ < C++11
|
||||
#define BENCHMARK_TEMPLATE(func, arg1)
|
||||
#endif
|
||||
#define BENCHMARK_TEMPLATE1(func, arg1)
|
||||
#define BENCHMARK_TEMPLATE2(func, arg1, arg2)
|
||||
```
|
||||
|
||||
### A Faster KeepRunning loop
|
||||
|
||||
In C++11 mode, a ranged-based for loop should be used in preference to
|
||||
the `KeepRunning` loop for running the benchmarks. For example:
|
||||
|
||||
```c++
|
||||
static void BM_Fast(benchmark::State &state) {
|
||||
for (auto _ : state) {
|
||||
FastOperation();
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_Fast);
|
||||
```
|
||||
|
||||
The reason the ranged-for loop is faster than using `KeepRunning`, is
|
||||
because `KeepRunning` requires a memory load and store of the iteration count
|
||||
ever iteration, whereas the ranged-for variant is able to keep the iteration count
|
||||
in a register.
|
||||
|
||||
For example, an empty inner loop of using the ranged-based for method looks like:
|
||||
|
||||
```asm
|
||||
# Loop Init
|
||||
mov rbx, qword ptr [r14 + 104]
|
||||
call benchmark::State::StartKeepRunning()
|
||||
test rbx, rbx
|
||||
je .LoopEnd
|
||||
.LoopHeader: # =>This Inner Loop Header: Depth=1
|
||||
add rbx, -1
|
||||
jne .LoopHeader
|
||||
.LoopEnd:
|
||||
```
|
||||
|
||||
Compared to an empty `KeepRunning` loop, which looks like:
|
||||
|
||||
```asm
|
||||
.LoopHeader: # in Loop: Header=BB0_3 Depth=1
|
||||
cmp byte ptr [rbx], 1
|
||||
jne .LoopInit
|
||||
.LoopBody: # =>This Inner Loop Header: Depth=1
|
||||
mov rax, qword ptr [rbx + 8]
|
||||
lea rcx, [rax + 1]
|
||||
mov qword ptr [rbx + 8], rcx
|
||||
cmp rax, qword ptr [rbx + 104]
|
||||
jb .LoopHeader
|
||||
jmp .LoopEnd
|
||||
.LoopInit:
|
||||
mov rdi, rbx
|
||||
call benchmark::State::StartKeepRunning()
|
||||
jmp .LoopBody
|
||||
.LoopEnd:
|
||||
```
|
||||
|
||||
Unless C++03 compatibility is required, the ranged-for variant of writing
|
||||
the benchmark loop should be preferred.
|
||||
|
||||
## Passing arbitrary arguments to a benchmark
|
||||
In C++11 it is possible to define a benchmark that takes an arbitrary number
|
||||
of extra arguments. The `BENCHMARK_CAPTURE(func, test_case_name, ...args)`
|
||||
macro creates a benchmark that invokes `func` with the `benchmark::State` as
|
||||
the first argument followed by the specified `args...`.
|
||||
The `test_case_name` is appended to the name of the benchmark and
|
||||
should describe the values passed.
|
||||
|
||||
```c++
|
||||
template <class ...ExtraArgs>
|
||||
void BM_takes_args(benchmark::State& state, ExtraArgs&&... extra_args) {
|
||||
[...]
|
||||
}
|
||||
// Registers a benchmark named "BM_takes_args/int_string_test" that passes
|
||||
// the specified values to `extra_args`.
|
||||
BENCHMARK_CAPTURE(BM_takes_args, int_string_test, 42, std::string("abc"));
|
||||
```
|
||||
Note that elements of `...args` may refer to global variables. Users should
|
||||
avoid modifying global state inside of a benchmark.
|
||||
|
||||
## Using RegisterBenchmark(name, fn, args...)
|
||||
|
||||
The `RegisterBenchmark(name, func, args...)` function provides an alternative
|
||||
way to create and register benchmarks.
|
||||
`RegisterBenchmark(name, func, args...)` creates, registers, and returns a
|
||||
pointer to a new benchmark with the specified `name` that invokes
|
||||
`func(st, args...)` where `st` is a `benchmark::State` object.
|
||||
|
||||
Unlike the `BENCHMARK` registration macros, which can only be used at the global
|
||||
scope, the `RegisterBenchmark` can be called anywhere. This allows for
|
||||
benchmark tests to be registered programmatically.
|
||||
|
||||
Additionally `RegisterBenchmark` allows any callable object to be registered
|
||||
as a benchmark. Including capturing lambdas and function objects.
|
||||
|
||||
For Example:
|
||||
```c++
|
||||
auto BM_test = [](benchmark::State& st, auto Inputs) { /* ... */ };
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
for (auto& test_input : { /* ... */ })
|
||||
benchmark::RegisterBenchmark(test_input.name(), BM_test, test_input);
|
||||
benchmark::Initialize(&argc, argv);
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
||||
```
|
||||
|
||||
### Multithreaded benchmarks
|
||||
In a multithreaded test (benchmark invoked by multiple threads simultaneously),
|
||||
it is guaranteed that none of the threads will start until all have reached
|
||||
the start of the benchmark loop, and all will have finished before any thread
|
||||
exits the benchmark loop. (This behavior is also provided by the `KeepRunning()`
|
||||
API) As such, any global setup or teardown can be wrapped in a check against the thread
|
||||
index:
|
||||
|
||||
```c++
|
||||
static void BM_MultiThreaded(benchmark::State& state) {
|
||||
if (state.thread_index == 0) {
|
||||
// Setup code here.
|
||||
}
|
||||
for (auto _ : state) {
|
||||
// Run the test as normal.
|
||||
}
|
||||
if (state.thread_index == 0) {
|
||||
// Teardown code here.
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_MultiThreaded)->Threads(2);
|
||||
```
|
||||
|
||||
If the benchmarked code itself uses threads and you want to compare it to
|
||||
single-threaded code, you may want to use real-time ("wallclock") measurements
|
||||
for latency comparisons:
|
||||
|
||||
```c++
|
||||
BENCHMARK(BM_test)->Range(8, 8<<10)->UseRealTime();
|
||||
```
|
||||
|
||||
Without `UseRealTime`, CPU time is used by default.
|
||||
|
||||
|
||||
## Manual timing
|
||||
For benchmarking something for which neither CPU time nor real-time are
|
||||
correct or accurate enough, completely manual timing is supported using
|
||||
the `UseManualTime` function.
|
||||
|
||||
When `UseManualTime` is used, the benchmarked code must call
|
||||
`SetIterationTime` once per iteration of the benchmark loop to
|
||||
report the manually measured time.
|
||||
|
||||
An example use case for this is benchmarking GPU execution (e.g. OpenCL
|
||||
or CUDA kernels, OpenGL or Vulkan or Direct3D draw calls), which cannot
|
||||
be accurately measured using CPU time or real-time. Instead, they can be
|
||||
measured accurately using a dedicated API, and these measurement results
|
||||
can be reported back with `SetIterationTime`.
|
||||
|
||||
```c++
|
||||
static void BM_ManualTiming(benchmark::State& state) {
|
||||
int microseconds = state.range(0);
|
||||
std::chrono::duration<double, std::micro> sleep_duration {
|
||||
static_cast<double>(microseconds)
|
||||
};
|
||||
|
||||
for (auto _ : state) {
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
// Simulate some useful workload with a sleep
|
||||
std::this_thread::sleep_for(sleep_duration);
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
|
||||
auto elapsed_seconds =
|
||||
std::chrono::duration_cast<std::chrono::duration<double>>(
|
||||
end - start);
|
||||
|
||||
state.SetIterationTime(elapsed_seconds.count());
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_ManualTiming)->Range(1, 1<<17)->UseManualTime();
|
||||
```
|
||||
|
||||
### Preventing optimisation
|
||||
To prevent a value or expression from being optimized away by the compiler
|
||||
the `benchmark::DoNotOptimize(...)` and `benchmark::ClobberMemory()`
|
||||
functions can be used.
|
||||
|
||||
```c++
|
||||
static void BM_test(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
int x = 0;
|
||||
for (int i=0; i < 64; ++i) {
|
||||
benchmark::DoNotOptimize(x += i);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`DoNotOptimize(<expr>)` forces the *result* of `<expr>` to be stored in either
|
||||
memory or a register. For GNU based compilers it acts as read/write barrier
|
||||
for global memory. More specifically it forces the compiler to flush pending
|
||||
writes to memory and reload any other values as necessary.
|
||||
|
||||
Note that `DoNotOptimize(<expr>)` does not prevent optimizations on `<expr>`
|
||||
in any way. `<expr>` may even be removed entirely when the result is already
|
||||
known. For example:
|
||||
|
||||
```c++
|
||||
/* Example 1: `<expr>` is removed entirely. */
|
||||
int foo(int x) { return x + 42; }
|
||||
while (...) DoNotOptimize(foo(0)); // Optimized to DoNotOptimize(42);
|
||||
|
||||
/* Example 2: Result of '<expr>' is only reused */
|
||||
int bar(int) __attribute__((const));
|
||||
while (...) DoNotOptimize(bar(0)); // Optimized to:
|
||||
// int __result__ = bar(0);
|
||||
// while (...) DoNotOptimize(__result__);
|
||||
```
|
||||
|
||||
The second tool for preventing optimizations is `ClobberMemory()`. In essence
|
||||
`ClobberMemory()` forces the compiler to perform all pending writes to global
|
||||
memory. Memory managed by block scope objects must be "escaped" using
|
||||
`DoNotOptimize(...)` before it can be clobbered. In the below example
|
||||
`ClobberMemory()` prevents the call to `v.push_back(42)` from being optimized
|
||||
away.
|
||||
|
||||
```c++
|
||||
static void BM_vector_push_back(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
std::vector<int> v;
|
||||
v.reserve(1);
|
||||
benchmark::DoNotOptimize(v.data()); // Allow v.data() to be clobbered.
|
||||
v.push_back(42);
|
||||
benchmark::ClobberMemory(); // Force 42 to be written to memory.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note that `ClobberMemory()` is only available for GNU or MSVC based compilers.
|
||||
|
||||
### Set time unit manually
|
||||
If a benchmark runs a few milliseconds it may be hard to visually compare the
|
||||
measured times, since the output data is given in nanoseconds per default. In
|
||||
order to manually set the time unit, you can specify it manually:
|
||||
|
||||
```c++
|
||||
BENCHMARK(BM_test)->Unit(benchmark::kMillisecond);
|
||||
```
|
||||
|
||||
## Controlling number of iterations
|
||||
In all cases, the number of iterations for which the benchmark is run is
|
||||
governed by the amount of time the benchmark takes. Concretely, the number of
|
||||
iterations is at least one, not more than 1e9, until CPU time is greater than
|
||||
the minimum time, or the wallclock time is 5x minimum time. The minimum time is
|
||||
set as a flag `--benchmark_min_time` or per benchmark by calling `MinTime` on
|
||||
the registered benchmark object.
|
||||
|
||||
## Reporting the mean, median and standard deviation by repeated benchmarks
|
||||
By default each benchmark is run once and that single result is reported.
|
||||
However benchmarks are often noisy and a single result may not be representative
|
||||
of the overall behavior. For this reason it's possible to repeatedly rerun the
|
||||
benchmark.
|
||||
|
||||
The number of runs of each benchmark is specified globally by the
|
||||
`--benchmark_repetitions` flag or on a per benchmark basis by calling
|
||||
`Repetitions` on the registered benchmark object. When a benchmark is run more
|
||||
than once the mean, median and standard deviation of the runs will be reported.
|
||||
|
||||
Additionally the `--benchmark_report_aggregates_only={true|false}` flag or
|
||||
`ReportAggregatesOnly(bool)` function can be used to change how repeated tests
|
||||
are reported. By default the result of each repeated run is reported. When this
|
||||
option is `true` only the mean, median and standard deviation of the runs is reported.
|
||||
Calling `ReportAggregatesOnly(bool)` on a registered benchmark object overrides
|
||||
the value of the flag for that benchmark.
|
||||
|
||||
## User-defined statistics for repeated benchmarks
|
||||
While having mean, median and standard deviation is nice, this may not be
|
||||
enough for everyone. For example you may want to know what is the largest
|
||||
observation, e.g. because you have some real-time constraints. This is easy.
|
||||
The following code will specify a custom statistic to be calculated, defined
|
||||
by a lambda function.
|
||||
|
||||
```c++
|
||||
void BM_spin_empty(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
for (int x = 0; x < state.range(0); ++x) {
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(BM_spin_empty)
|
||||
->ComputeStatistics("max", [](const std::vector<double>& v) -> double {
|
||||
return *(std::max_element(std::begin(v), std::end(v)));
|
||||
})
|
||||
->Arg(512);
|
||||
```
|
||||
|
||||
## Fixtures
|
||||
Fixture tests are created by
|
||||
first defining a type that derives from `::benchmark::Fixture` and then
|
||||
creating/registering the tests using the following macros:
|
||||
|
||||
* `BENCHMARK_F(ClassName, Method)`
|
||||
* `BENCHMARK_DEFINE_F(ClassName, Method)`
|
||||
* `BENCHMARK_REGISTER_F(ClassName, Method)`
|
||||
|
||||
For Example:
|
||||
|
||||
```c++
|
||||
class MyFixture : public benchmark::Fixture {};
|
||||
|
||||
BENCHMARK_F(MyFixture, FooTest)(benchmark::State& st) {
|
||||
for (auto _ : st) {
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(MyFixture, BarTest)(benchmark::State& st) {
|
||||
for (auto _ : st) {
|
||||
...
|
||||
}
|
||||
}
|
||||
/* BarTest is NOT registered */
|
||||
BENCHMARK_REGISTER_F(MyFixture, BarTest)->Threads(2);
|
||||
/* BarTest is now registered */
|
||||
```
|
||||
|
||||
### Templated fixtures
|
||||
Also you can create templated fixture by using the following macros:
|
||||
|
||||
* `BENCHMARK_TEMPLATE_F(ClassName, Method, ...)`
|
||||
* `BENCHMARK_TEMPLATE_DEFINE_F(ClassName, Method, ...)`
|
||||
|
||||
For example:
|
||||
```c++
|
||||
template<typename T>
|
||||
class MyFixture : public benchmark::Fixture {};
|
||||
|
||||
BENCHMARK_TEMPLATE_F(MyFixture, IntTest, int)(benchmark::State& st) {
|
||||
for (auto _ : st) {
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_TEMPLATE_DEFINE_F(MyFixture, DoubleTest, double)(benchmark::State& st) {
|
||||
for (auto _ : st) {
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_REGISTER_F(MyFixture, DoubleTest)->Threads(2);
|
||||
```
|
||||
|
||||
## User-defined counters
|
||||
|
||||
You can add your own counters with user-defined names. The example below
|
||||
will add columns "Foo", "Bar" and "Baz" in its output:
|
||||
|
||||
```c++
|
||||
static void UserCountersExample1(benchmark::State& state) {
|
||||
double numFoos = 0, numBars = 0, numBazs = 0;
|
||||
for (auto _ : state) {
|
||||
// ... count Foo,Bar,Baz events
|
||||
}
|
||||
state.counters["Foo"] = numFoos;
|
||||
state.counters["Bar"] = numBars;
|
||||
state.counters["Baz"] = numBazs;
|
||||
}
|
||||
```
|
||||
|
||||
The `state.counters` object is a `std::map` with `std::string` keys
|
||||
and `Counter` values. The latter is a `double`-like class, via an implicit
|
||||
conversion to `double&`. Thus you can use all of the standard arithmetic
|
||||
assignment operators (`=,+=,-=,*=,/=`) to change the value of each counter.
|
||||
|
||||
In multithreaded benchmarks, each counter is set on the calling thread only.
|
||||
When the benchmark finishes, the counters from each thread will be summed;
|
||||
the resulting sum is the value which will be shown for the benchmark.
|
||||
|
||||
The `Counter` constructor accepts two parameters: the value as a `double`
|
||||
and a bit flag which allows you to show counters as rates and/or as
|
||||
per-thread averages:
|
||||
|
||||
```c++
|
||||
// sets a simple counter
|
||||
state.counters["Foo"] = numFoos;
|
||||
|
||||
// Set the counter as a rate. It will be presented divided
|
||||
// by the duration of the benchmark.
|
||||
state.counters["FooRate"] = Counter(numFoos, benchmark::Counter::kIsRate);
|
||||
|
||||
// Set the counter as a thread-average quantity. It will
|
||||
// be presented divided by the number of threads.
|
||||
state.counters["FooAvg"] = Counter(numFoos, benchmark::Counter::kAvgThreads);
|
||||
|
||||
// There's also a combined flag:
|
||||
state.counters["FooAvgRate"] = Counter(numFoos,benchmark::Counter::kAvgThreadsRate);
|
||||
```
|
||||
|
||||
When you're compiling in C++11 mode or later you can use `insert()` with
|
||||
`std::initializer_list`:
|
||||
|
||||
```c++
|
||||
// With C++11, this can be done:
|
||||
state.counters.insert({{"Foo", numFoos}, {"Bar", numBars}, {"Baz", numBazs}});
|
||||
// ... instead of:
|
||||
state.counters["Foo"] = numFoos;
|
||||
state.counters["Bar"] = numBars;
|
||||
state.counters["Baz"] = numBazs;
|
||||
```
|
||||
|
||||
### Counter reporting
|
||||
|
||||
When using the console reporter, by default, user counters are are printed at
|
||||
the end after the table, the same way as ``bytes_processed`` and
|
||||
``items_processed``. This is best for cases in which there are few counters,
|
||||
or where there are only a couple of lines per benchmark. Here's an example of
|
||||
the default output:
|
||||
|
||||
```
|
||||
------------------------------------------------------------------------------
|
||||
Benchmark Time CPU Iterations UserCounters...
|
||||
------------------------------------------------------------------------------
|
||||
BM_UserCounter/threads:8 2248 ns 10277 ns 68808 Bar=16 Bat=40 Baz=24 Foo=8
|
||||
BM_UserCounter/threads:1 9797 ns 9788 ns 71523 Bar=2 Bat=5 Baz=3 Foo=1024m
|
||||
BM_UserCounter/threads:2 4924 ns 9842 ns 71036 Bar=4 Bat=10 Baz=6 Foo=2
|
||||
BM_UserCounter/threads:4 2589 ns 10284 ns 68012 Bar=8 Bat=20 Baz=12 Foo=4
|
||||
BM_UserCounter/threads:8 2212 ns 10287 ns 68040 Bar=16 Bat=40 Baz=24 Foo=8
|
||||
BM_UserCounter/threads:16 1782 ns 10278 ns 68144 Bar=32 Bat=80 Baz=48 Foo=16
|
||||
BM_UserCounter/threads:32 1291 ns 10296 ns 68256 Bar=64 Bat=160 Baz=96 Foo=32
|
||||
BM_UserCounter/threads:4 2615 ns 10307 ns 68040 Bar=8 Bat=20 Baz=12 Foo=4
|
||||
BM_Factorial 26 ns 26 ns 26608979 40320
|
||||
BM_Factorial/real_time 26 ns 26 ns 26587936 40320
|
||||
BM_CalculatePiRange/1 16 ns 16 ns 45704255 0
|
||||
BM_CalculatePiRange/8 73 ns 73 ns 9520927 3.28374
|
||||
BM_CalculatePiRange/64 609 ns 609 ns 1140647 3.15746
|
||||
BM_CalculatePiRange/512 4900 ns 4901 ns 142696 3.14355
|
||||
```
|
||||
|
||||
If this doesn't suit you, you can print each counter as a table column by
|
||||
passing the flag `--benchmark_counters_tabular=true` to the benchmark
|
||||
application. This is best for cases in which there are a lot of counters, or
|
||||
a lot of lines per individual benchmark. Note that this will trigger a
|
||||
reprinting of the table header any time the counter set changes between
|
||||
individual benchmarks. Here's an example of corresponding output when
|
||||
`--benchmark_counters_tabular=true` is passed:
|
||||
|
||||
```
|
||||
---------------------------------------------------------------------------------------
|
||||
Benchmark Time CPU Iterations Bar Bat Baz Foo
|
||||
---------------------------------------------------------------------------------------
|
||||
BM_UserCounter/threads:8 2198 ns 9953 ns 70688 16 40 24 8
|
||||
BM_UserCounter/threads:1 9504 ns 9504 ns 73787 2 5 3 1
|
||||
BM_UserCounter/threads:2 4775 ns 9550 ns 72606 4 10 6 2
|
||||
BM_UserCounter/threads:4 2508 ns 9951 ns 70332 8 20 12 4
|
||||
BM_UserCounter/threads:8 2055 ns 9933 ns 70344 16 40 24 8
|
||||
BM_UserCounter/threads:16 1610 ns 9946 ns 70720 32 80 48 16
|
||||
BM_UserCounter/threads:32 1192 ns 9948 ns 70496 64 160 96 32
|
||||
BM_UserCounter/threads:4 2506 ns 9949 ns 70332 8 20 12 4
|
||||
--------------------------------------------------------------
|
||||
Benchmark Time CPU Iterations
|
||||
--------------------------------------------------------------
|
||||
BM_Factorial 26 ns 26 ns 26392245 40320
|
||||
BM_Factorial/real_time 26 ns 26 ns 26494107 40320
|
||||
BM_CalculatePiRange/1 15 ns 15 ns 45571597 0
|
||||
BM_CalculatePiRange/8 74 ns 74 ns 9450212 3.28374
|
||||
BM_CalculatePiRange/64 595 ns 595 ns 1173901 3.15746
|
||||
BM_CalculatePiRange/512 4752 ns 4752 ns 147380 3.14355
|
||||
BM_CalculatePiRange/4k 37970 ns 37972 ns 18453 3.14184
|
||||
BM_CalculatePiRange/32k 303733 ns 303744 ns 2305 3.14162
|
||||
BM_CalculatePiRange/256k 2434095 ns 2434186 ns 288 3.1416
|
||||
BM_CalculatePiRange/1024k 9721140 ns 9721413 ns 71 3.14159
|
||||
BM_CalculatePi/threads:8 2255 ns 9943 ns 70936
|
||||
```
|
||||
Note above the additional header printed when the benchmark changes from
|
||||
``BM_UserCounter`` to ``BM_Factorial``. This is because ``BM_Factorial`` does
|
||||
not have the same counter set as ``BM_UserCounter``.
|
||||
|
||||
## Exiting Benchmarks in Error
|
||||
|
||||
When errors caused by external influences, such as file I/O and network
|
||||
communication, occur within a benchmark the
|
||||
`State::SkipWithError(const char* msg)` function can be used to skip that run
|
||||
of benchmark and report the error. Note that only future iterations of the
|
||||
`KeepRunning()` are skipped. For the ranged-for version of the benchmark loop
|
||||
Users must explicitly exit the loop, otherwise all iterations will be performed.
|
||||
Users may explicitly return to exit the benchmark immediately.
|
||||
|
||||
The `SkipWithError(...)` function may be used at any point within the benchmark,
|
||||
including before and after the benchmark loop.
|
||||
|
||||
For example:
|
||||
|
||||
```c++
|
||||
static void BM_test(benchmark::State& state) {
|
||||
auto resource = GetResource();
|
||||
if (!resource.good()) {
|
||||
state.SkipWithError("Resource is not good!");
|
||||
// KeepRunning() loop will not be entered.
|
||||
}
|
||||
for (state.KeepRunning()) {
|
||||
auto data = resource.read_data();
|
||||
if (!resource.good()) {
|
||||
state.SkipWithError("Failed to read data!");
|
||||
break; // Needed to skip the rest of the iteration.
|
||||
}
|
||||
do_stuff(data);
|
||||
}
|
||||
}
|
||||
|
||||
static void BM_test_ranged_fo(benchmark::State & state) {
|
||||
state.SkipWithError("test will not be entered");
|
||||
for (auto _ : state) {
|
||||
state.SkipWithError("Failed!");
|
||||
break; // REQUIRED to prevent all further iterations.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Running a subset of the benchmarks
|
||||
|
||||
The `--benchmark_filter=<regex>` option can be used to only run the benchmarks
|
||||
which match the specified `<regex>`. For example:
|
||||
|
||||
```bash
|
||||
$ ./run_benchmarks.x --benchmark_filter=BM_memcpy/32
|
||||
Run on (1 X 2300 MHz CPU )
|
||||
2016-06-25 19:34:24
|
||||
Benchmark Time CPU Iterations
|
||||
----------------------------------------------------
|
||||
BM_memcpy/32 11 ns 11 ns 79545455
|
||||
BM_memcpy/32k 2181 ns 2185 ns 324074
|
||||
BM_memcpy/32 12 ns 12 ns 54687500
|
||||
BM_memcpy/32k 1834 ns 1837 ns 357143
|
||||
```
|
||||
|
||||
|
||||
## Output Formats
|
||||
The library supports multiple output formats. Use the
|
||||
`--benchmark_format=<console|json|csv>` flag to set the format type. `console`
|
||||
is the default format.
|
||||
|
||||
The Console format is intended to be a human readable format. By default
|
||||
the format generates color output. Context is output on stderr and the
|
||||
tabular data on stdout. Example tabular output looks like:
|
||||
```
|
||||
Benchmark Time(ns) CPU(ns) Iterations
|
||||
----------------------------------------------------------------------
|
||||
BM_SetInsert/1024/1 28928 29349 23853 133.097kB/s 33.2742k items/s
|
||||
BM_SetInsert/1024/8 32065 32913 21375 949.487kB/s 237.372k items/s
|
||||
BM_SetInsert/1024/10 33157 33648 21431 1.13369MB/s 290.225k items/s
|
||||
```
|
||||
|
||||
The JSON format outputs human readable json split into two top level attributes.
|
||||
The `context` attribute contains information about the run in general, including
|
||||
information about the CPU and the date.
|
||||
The `benchmarks` attribute contains a list of every benchmark run. Example json
|
||||
output looks like:
|
||||
```json
|
||||
{
|
||||
"context": {
|
||||
"date": "2015/03/17-18:40:25",
|
||||
"num_cpus": 40,
|
||||
"mhz_per_cpu": 2801,
|
||||
"cpu_scaling_enabled": false,
|
||||
"build_type": "debug"
|
||||
},
|
||||
"benchmarks": [
|
||||
{
|
||||
"name": "BM_SetInsert/1024/1",
|
||||
"iterations": 94877,
|
||||
"real_time": 29275,
|
||||
"cpu_time": 29836,
|
||||
"bytes_per_second": 134066,
|
||||
"items_per_second": 33516
|
||||
},
|
||||
{
|
||||
"name": "BM_SetInsert/1024/8",
|
||||
"iterations": 21609,
|
||||
"real_time": 32317,
|
||||
"cpu_time": 32429,
|
||||
"bytes_per_second": 986770,
|
||||
"items_per_second": 246693
|
||||
},
|
||||
{
|
||||
"name": "BM_SetInsert/1024/10",
|
||||
"iterations": 21393,
|
||||
"real_time": 32724,
|
||||
"cpu_time": 33355,
|
||||
"bytes_per_second": 1199226,
|
||||
"items_per_second": 299807
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The CSV format outputs comma-separated values. The `context` is output on stderr
|
||||
and the CSV itself on stdout. Example CSV output looks like:
|
||||
```
|
||||
name,iterations,real_time,cpu_time,bytes_per_second,items_per_second,label
|
||||
"BM_SetInsert/1024/1",65465,17890.7,8407.45,475768,118942,
|
||||
"BM_SetInsert/1024/8",116606,18810.1,9766.64,3.27646e+06,819115,
|
||||
"BM_SetInsert/1024/10",106365,17238.4,8421.53,4.74973e+06,1.18743e+06,
|
||||
```
|
||||
|
||||
## Output Files
|
||||
The library supports writing the output of the benchmark to a file specified
|
||||
by `--benchmark_out=<filename>`. The format of the output can be specified
|
||||
using `--benchmark_out_format={json|console|csv}`. Specifying
|
||||
`--benchmark_out` does not suppress the console output.
|
||||
|
||||
## Debug vs Release
|
||||
By default, benchmark builds as a debug library. You will see a warning in the output when this is the case. To build it as a release library instead, use:
|
||||
|
||||
```
|
||||
cmake -DCMAKE_BUILD_TYPE=Release
|
||||
```
|
||||
|
||||
To enable link-time optimisation, use
|
||||
|
||||
```
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DBENCHMARK_ENABLE_LTO=true
|
||||
```
|
||||
|
||||
If you are using gcc, you might need to set `GCC_AR` and `GCC_RANLIB` cmake cache variables, if autodetection fails.
|
||||
If you are using clang, you may need to set `LLVMAR_EXECUTABLE`, `LLVMNM_EXECUTABLE` and `LLVMRANLIB_EXECUTABLE` cmake cache variables.
|
||||
|
||||
## Linking against the library
|
||||
|
||||
When the library is built using GCC it is necessary to link with `-pthread`,
|
||||
due to how GCC implements `std::thread`.
|
||||
|
||||
For GCC 4.x failing to link to pthreads will lead to runtime exceptions, not linker errors.
|
||||
See [issue #67](https://github.com/google/benchmark/issues/67) for more details.
|
||||
|
||||
## Compiler Support
|
||||
|
||||
Google Benchmark uses C++11 when building the library. As such we require
|
||||
a modern C++ toolchain, both compiler and standard library.
|
||||
|
||||
The following minimum versions are strongly recommended build the library:
|
||||
|
||||
* GCC 4.8
|
||||
* Clang 3.4
|
||||
* Visual Studio 2013
|
||||
* Intel 2015 Update 1
|
||||
|
||||
Anything older *may* work.
|
||||
|
||||
Note: Using the library and its headers in C++03 is supported. C++11 is only
|
||||
required to build the library.
|
||||
|
||||
## Disable CPU frequency scaling
|
||||
If you see this error:
|
||||
```
|
||||
***WARNING*** CPU scaling is enabled, the benchmark real time measurements may be noisy and will incur extra overhead.
|
||||
```
|
||||
you might want to disable the CPU frequency scaling while running the benchmark:
|
||||
```bash
|
||||
sudo cpupower frequency-set --governor performance
|
||||
./mybench
|
||||
sudo cpupower frequency-set --governor powersave
|
||||
```
|
||||
|
||||
# Known Issues
|
||||
|
||||
### Windows with CMake
|
||||
|
||||
* Users must manually link `shlwapi.lib`. Failure to do so may result
|
||||
in unresolved symbols.
|
||||
|
||||
### Solaris
|
||||
|
||||
* Users must explicitly link with kstat library (-lkstat compilation flag).
|
||||
7
benchmarks/thirdparty/benchmark/WORKSPACE
vendored
7
benchmarks/thirdparty/benchmark/WORKSPACE
vendored
@@ -1,7 +0,0 @@
|
||||
workspace(name = "com_github_google_benchmark")
|
||||
|
||||
http_archive(
|
||||
name = "com_google_googletest",
|
||||
urls = ["https://github.com/google/googletest/archive/3f0cf6b62ad1eb50d8736538363d3580dd640c3e.zip"],
|
||||
strip_prefix = "googletest-3f0cf6b62ad1eb50d8736538363d3580dd640c3e",
|
||||
)
|
||||
56
benchmarks/thirdparty/benchmark/appveyor.yml
vendored
56
benchmarks/thirdparty/benchmark/appveyor.yml
vendored
@@ -1,56 +0,0 @@
|
||||
version: '{build}'
|
||||
|
||||
image: Visual Studio 2017
|
||||
|
||||
configuration:
|
||||
- Debug
|
||||
- Release
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- compiler: msvc-15-seh
|
||||
generator: "Visual Studio 15 2017"
|
||||
|
||||
- compiler: msvc-15-seh
|
||||
generator: "Visual Studio 15 2017 Win64"
|
||||
|
||||
- compiler: msvc-14-seh
|
||||
generator: "Visual Studio 14 2015"
|
||||
|
||||
- compiler: msvc-14-seh
|
||||
generator: "Visual Studio 14 2015 Win64"
|
||||
|
||||
- compiler: msvc-12-seh
|
||||
generator: "Visual Studio 12 2013"
|
||||
|
||||
- compiler: msvc-12-seh
|
||||
generator: "Visual Studio 12 2013 Win64"
|
||||
|
||||
- compiler: gcc-5.3.0-posix
|
||||
generator: "MinGW Makefiles"
|
||||
cxx_path: 'C:\mingw-w64\i686-5.3.0-posix-dwarf-rt_v4-rev0\mingw32\bin'
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
||||
install:
|
||||
# git bash conflicts with MinGW makefiles
|
||||
- if "%generator%"=="MinGW Makefiles" (set "PATH=%PATH:C:\Program Files\Git\usr\bin;=%")
|
||||
- if not "%cxx_path%"=="" (set "PATH=%PATH%;%cxx_path%")
|
||||
|
||||
build_script:
|
||||
- md _build -Force
|
||||
- cd _build
|
||||
- echo %configuration%
|
||||
- cmake -G "%generator%" "-DCMAKE_BUILD_TYPE=%configuration%" -DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON ..
|
||||
- cmake --build . --config %configuration%
|
||||
|
||||
test_script:
|
||||
- ctest -c %configuration% --timeout 300 --output-on-failure
|
||||
|
||||
artifacts:
|
||||
- path: '_build/CMakeFiles/*.log'
|
||||
name: logs
|
||||
- path: '_build/Testing/**/*.xml'
|
||||
name: test_results
|
||||
@@ -1,74 +0,0 @@
|
||||
# - Adds a compiler flag if it is supported by the compiler
|
||||
#
|
||||
# This function checks that the supplied compiler flag is supported and then
|
||||
# adds it to the corresponding compiler flags
|
||||
#
|
||||
# add_cxx_compiler_flag(<FLAG> [<VARIANT>])
|
||||
#
|
||||
# - Example
|
||||
#
|
||||
# include(AddCXXCompilerFlag)
|
||||
# add_cxx_compiler_flag(-Wall)
|
||||
# add_cxx_compiler_flag(-no-strict-aliasing RELEASE)
|
||||
# Requires CMake 2.6+
|
||||
|
||||
if(__add_cxx_compiler_flag)
|
||||
return()
|
||||
endif()
|
||||
set(__add_cxx_compiler_flag INCLUDED)
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
function(mangle_compiler_flag FLAG OUTPUT)
|
||||
string(TOUPPER "HAVE_CXX_FLAG_${FLAG}" SANITIZED_FLAG)
|
||||
string(REPLACE "+" "X" SANITIZED_FLAG ${SANITIZED_FLAG})
|
||||
string(REGEX REPLACE "[^A-Za-z_0-9]" "_" SANITIZED_FLAG ${SANITIZED_FLAG})
|
||||
string(REGEX REPLACE "_+" "_" SANITIZED_FLAG ${SANITIZED_FLAG})
|
||||
set(${OUTPUT} "${SANITIZED_FLAG}" PARENT_SCOPE)
|
||||
endfunction(mangle_compiler_flag)
|
||||
|
||||
function(add_cxx_compiler_flag FLAG)
|
||||
mangle_compiler_flag("${FLAG}" MANGLED_FLAG)
|
||||
set(OLD_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${FLAG}")
|
||||
check_cxx_compiler_flag("${FLAG}" ${MANGLED_FLAG})
|
||||
set(CMAKE_REQUIRED_FLAGS "${OLD_CMAKE_REQUIRED_FLAGS}")
|
||||
if(${MANGLED_FLAG})
|
||||
set(VARIANT ${ARGV1})
|
||||
if(ARGV1)
|
||||
string(TOUPPER "_${VARIANT}" VARIANT)
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS${VARIANT} "${CMAKE_CXX_FLAGS${VARIANT}} ${BENCHMARK_CXX_FLAGS${VARIANT}} ${FLAG}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(add_required_cxx_compiler_flag FLAG)
|
||||
mangle_compiler_flag("${FLAG}" MANGLED_FLAG)
|
||||
set(OLD_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${FLAG}")
|
||||
check_cxx_compiler_flag("${FLAG}" ${MANGLED_FLAG})
|
||||
set(CMAKE_REQUIRED_FLAGS "${OLD_CMAKE_REQUIRED_FLAGS}")
|
||||
if(${MANGLED_FLAG})
|
||||
set(VARIANT ${ARGV1})
|
||||
if(ARGV1)
|
||||
string(TOUPPER "_${VARIANT}" VARIANT)
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS${VARIANT} "${CMAKE_CXX_FLAGS${VARIANT}} ${FLAG}" PARENT_SCOPE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${FLAG}" PARENT_SCOPE)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${FLAG}" PARENT_SCOPE)
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${FLAG}" PARENT_SCOPE)
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${FLAG}" PARENT_SCOPE)
|
||||
else()
|
||||
message(FATAL_ERROR "Required flag '${FLAG}' is not supported by the compiler")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(check_cxx_warning_flag FLAG)
|
||||
mangle_compiler_flag("${FLAG}" MANGLED_FLAG)
|
||||
set(OLD_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
|
||||
# Add -Werror to ensure the compiler generates an error if the warning flag
|
||||
# doesn't exist.
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Werror ${FLAG}")
|
||||
check_cxx_compiler_flag("${FLAG}" ${MANGLED_FLAG})
|
||||
set(CMAKE_REQUIRED_FLAGS "${OLD_CMAKE_REQUIRED_FLAGS}")
|
||||
endfunction()
|
||||
@@ -1,64 +0,0 @@
|
||||
# - Compile and run code to check for C++ features
|
||||
#
|
||||
# This functions compiles a source file under the `cmake` folder
|
||||
# and adds the corresponding `HAVE_[FILENAME]` flag to the CMake
|
||||
# environment
|
||||
#
|
||||
# cxx_feature_check(<FLAG> [<VARIANT>])
|
||||
#
|
||||
# - Example
|
||||
#
|
||||
# include(CXXFeatureCheck)
|
||||
# cxx_feature_check(STD_REGEX)
|
||||
# Requires CMake 2.8.12+
|
||||
|
||||
if(__cxx_feature_check)
|
||||
return()
|
||||
endif()
|
||||
set(__cxx_feature_check INCLUDED)
|
||||
|
||||
function(cxx_feature_check FILE)
|
||||
string(TOLOWER ${FILE} FILE)
|
||||
string(TOUPPER ${FILE} VAR)
|
||||
string(TOUPPER "HAVE_${VAR}" FEATURE)
|
||||
if (DEFINED HAVE_${VAR})
|
||||
set(HAVE_${VAR} 1 PARENT_SCOPE)
|
||||
add_definitions(-DHAVE_${VAR})
|
||||
return()
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED COMPILE_${FEATURE})
|
||||
message("-- Performing Test ${FEATURE}")
|
||||
if(CMAKE_CROSSCOMPILING)
|
||||
try_compile(COMPILE_${FEATURE}
|
||||
${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${FILE}.cpp
|
||||
CMAKE_FLAGS ${BENCHMARK_CXX_LINKER_FLAGS}
|
||||
LINK_LIBRARIES ${BENCHMARK_CXX_LIBRARIES})
|
||||
if(COMPILE_${FEATURE})
|
||||
message(WARNING
|
||||
"If you see build failures due to cross compilation, try setting HAVE_${VAR} to 0")
|
||||
set(RUN_${FEATURE} 0)
|
||||
else()
|
||||
set(RUN_${FEATURE} 1)
|
||||
endif()
|
||||
else()
|
||||
message("-- Performing Test ${FEATURE}")
|
||||
try_run(RUN_${FEATURE} COMPILE_${FEATURE}
|
||||
${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${FILE}.cpp
|
||||
CMAKE_FLAGS ${BENCHMARK_CXX_LINKER_FLAGS}
|
||||
LINK_LIBRARIES ${BENCHMARK_CXX_LIBRARIES})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(RUN_${FEATURE} EQUAL 0)
|
||||
message("-- Performing Test ${FEATURE} -- success")
|
||||
set(HAVE_${VAR} 1 PARENT_SCOPE)
|
||||
add_definitions(-DHAVE_${VAR})
|
||||
else()
|
||||
if(NOT COMPILE_${FEATURE})
|
||||
message("-- Performing Test ${FEATURE} -- failed to compile")
|
||||
else()
|
||||
message("-- Performing Test ${FEATURE} -- compiled but failed to run")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
@@ -1 +0,0 @@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake")
|
||||
@@ -1,54 +0,0 @@
|
||||
# - Returns a version string from Git tags
|
||||
#
|
||||
# This function inspects the annotated git tags for the project and returns a string
|
||||
# into a CMake variable
|
||||
#
|
||||
# get_git_version(<var>)
|
||||
#
|
||||
# - Example
|
||||
#
|
||||
# include(GetGitVersion)
|
||||
# get_git_version(GIT_VERSION)
|
||||
#
|
||||
# Requires CMake 2.8.11+
|
||||
find_package(Git)
|
||||
|
||||
if(__get_git_version)
|
||||
return()
|
||||
endif()
|
||||
set(__get_git_version INCLUDED)
|
||||
|
||||
function(get_git_version var)
|
||||
if(GIT_EXECUTABLE)
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} describe --match "v[0-9]*.[0-9]*.[0-9]*" --abbrev=8
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
RESULT_VARIABLE status
|
||||
OUTPUT_VARIABLE GIT_VERSION
|
||||
ERROR_QUIET)
|
||||
if(${status})
|
||||
set(GIT_VERSION "v0.0.0")
|
||||
else()
|
||||
string(STRIP ${GIT_VERSION} GIT_VERSION)
|
||||
string(REGEX REPLACE "-[0-9]+-g" "-" GIT_VERSION ${GIT_VERSION})
|
||||
endif()
|
||||
|
||||
# Work out if the repository is dirty
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} update-index -q --refresh
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
OUTPUT_QUIET
|
||||
ERROR_QUIET)
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} diff-index --name-only HEAD --
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE GIT_DIFF_INDEX
|
||||
ERROR_QUIET)
|
||||
string(COMPARE NOTEQUAL "${GIT_DIFF_INDEX}" "" GIT_DIRTY)
|
||||
if (${GIT_DIRTY})
|
||||
set(GIT_VERSION "${GIT_VERSION}-dirty")
|
||||
endif()
|
||||
else()
|
||||
set(GIT_VERSION "v0.0.0")
|
||||
endif()
|
||||
|
||||
message("-- git Version: ${GIT_VERSION}")
|
||||
set(${var} ${GIT_VERSION} PARENT_SCOPE)
|
||||
endfunction()
|
||||
@@ -1,113 +0,0 @@
|
||||
|
||||
include(split_list)
|
||||
|
||||
macro(build_external_gtest)
|
||||
include(ExternalProject)
|
||||
set(GTEST_FLAGS "")
|
||||
if (BENCHMARK_USE_LIBCXX)
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
list(APPEND GTEST_FLAGS -stdlib=libc++)
|
||||
else()
|
||||
message(WARNING "Unsupported compiler (${CMAKE_CXX_COMPILER}) when using libc++")
|
||||
endif()
|
||||
endif()
|
||||
if (BENCHMARK_BUILD_32_BITS)
|
||||
list(APPEND GTEST_FLAGS -m32)
|
||||
endif()
|
||||
if (NOT "${CMAKE_CXX_FLAGS}" STREQUAL "")
|
||||
list(APPEND GTEST_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
endif()
|
||||
string(TOUPPER "${CMAKE_BUILD_TYPE}" GTEST_BUILD_TYPE)
|
||||
if ("${GTEST_BUILD_TYPE}" STREQUAL "COVERAGE")
|
||||
set(GTEST_BUILD_TYPE "DEBUG")
|
||||
endif()
|
||||
# FIXME: Since 10/Feb/2017 the googletest trunk has had a bug where
|
||||
# -Werror=unused-function fires during the build on OS X. This is a temporary
|
||||
# workaround to keep our travis bots from failing. It should be removed
|
||||
# once gtest is fixed.
|
||||
if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
list(APPEND GTEST_FLAGS "-Wno-unused-function")
|
||||
endif()
|
||||
split_list(GTEST_FLAGS)
|
||||
set(EXCLUDE_FROM_ALL_OPT "")
|
||||
set(EXCLUDE_FROM_ALL_VALUE "")
|
||||
if (${CMAKE_VERSION} VERSION_GREATER "3.0.99")
|
||||
set(EXCLUDE_FROM_ALL_OPT "EXCLUDE_FROM_ALL")
|
||||
set(EXCLUDE_FROM_ALL_VALUE "ON")
|
||||
endif()
|
||||
ExternalProject_Add(googletest
|
||||
${EXCLUDE_FROM_ALL_OPT} ${EXCLUDE_FROM_ALL_VALUE}
|
||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||
GIT_TAG master
|
||||
PREFIX "${CMAKE_BINARY_DIR}/googletest"
|
||||
INSTALL_DIR "${CMAKE_BINARY_DIR}/googletest"
|
||||
CMAKE_CACHE_ARGS
|
||||
-DCMAKE_BUILD_TYPE:STRING=${GTEST_BUILD_TYPE}
|
||||
-DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER}
|
||||
-DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
|
||||
-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
||||
-DCMAKE_INSTALL_LIBDIR:PATH=<INSTALL_DIR>/lib
|
||||
-DCMAKE_CXX_FLAGS:STRING=${GTEST_FLAGS}
|
||||
-Dgtest_force_shared_crt:BOOL=ON
|
||||
)
|
||||
|
||||
ExternalProject_Get_Property(googletest install_dir)
|
||||
set(GTEST_INCLUDE_DIRS ${install_dir}/include)
|
||||
file(MAKE_DIRECTORY ${GTEST_INCLUDE_DIRS})
|
||||
|
||||
set(LIB_SUFFIX "${CMAKE_STATIC_LIBRARY_SUFFIX}")
|
||||
set(LIB_PREFIX "${CMAKE_STATIC_LIBRARY_PREFIX}")
|
||||
if("${GTEST_BUILD_TYPE}" STREQUAL "DEBUG")
|
||||
set(LIB_SUFFIX "d${CMAKE_STATIC_LIBRARY_SUFFIX}")
|
||||
endif()
|
||||
|
||||
# Use gmock_main instead of gtest_main because it initializes gtest as well.
|
||||
# Note: The libraries are listed in reverse order of their dependancies.
|
||||
foreach(LIB gtest gmock gmock_main)
|
||||
add_library(${LIB} UNKNOWN IMPORTED)
|
||||
set_target_properties(${LIB} PROPERTIES
|
||||
IMPORTED_LOCATION ${install_dir}/lib/${LIB_PREFIX}${LIB}${LIB_SUFFIX}
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${GTEST_INCLUDE_DIRS}
|
||||
INTERFACE_LINK_LIBRARIES "${GTEST_BOTH_LIBRARIES}"
|
||||
)
|
||||
add_dependencies(${LIB} googletest)
|
||||
list(APPEND GTEST_BOTH_LIBRARIES ${LIB})
|
||||
endforeach()
|
||||
endmacro(build_external_gtest)
|
||||
|
||||
if (BENCHMARK_ENABLE_GTEST_TESTS)
|
||||
if (IS_DIRECTORY ${CMAKE_SOURCE_DIR}/googletest)
|
||||
set(GTEST_ROOT "${CMAKE_SOURCE_DIR}/googletest")
|
||||
set(INSTALL_GTEST OFF CACHE INTERNAL "")
|
||||
set(INSTALL_GMOCK OFF CACHE INTERNAL "")
|
||||
add_subdirectory(${CMAKE_SOURCE_DIR}/googletest)
|
||||
set(GTEST_BOTH_LIBRARIES gtest gmock gmock_main)
|
||||
foreach(HEADER test mock)
|
||||
# CMake 2.8 and older don't respect INTERFACE_INCLUDE_DIRECTORIES, so we
|
||||
# have to add the paths ourselves.
|
||||
set(HFILE g${HEADER}/g${HEADER}.h)
|
||||
set(HPATH ${GTEST_ROOT}/google${HEADER}/include)
|
||||
find_path(HEADER_PATH_${HEADER} ${HFILE}
|
||||
NO_DEFAULT_PATHS
|
||||
HINTS ${HPATH}
|
||||
)
|
||||
if (NOT HEADER_PATH_${HEADER})
|
||||
message(FATAL_ERROR "Failed to find header ${HFILE} in ${HPATH}")
|
||||
endif()
|
||||
list(APPEND GTEST_INCLUDE_DIRS ${HEADER_PATH_${HEADER}})
|
||||
endforeach()
|
||||
elseif(BENCHMARK_DOWNLOAD_DEPENDENCIES)
|
||||
build_external_gtest()
|
||||
else()
|
||||
find_package(GTest REQUIRED)
|
||||
find_path(GMOCK_INCLUDE_DIRS gmock/gmock.h
|
||||
HINTS ${GTEST_INCLUDE_DIRS})
|
||||
if (NOT GMOCK_INCLUDE_DIRS)
|
||||
message(FATAL_ERROR "Failed to find header gmock/gmock.h with hint ${GTEST_INCLUDE_DIRS}")
|
||||
endif()
|
||||
set(GTEST_INCLUDE_DIRS ${GTEST_INCLUDE_DIRS} ${GMOCK_INCLUDE_DIRS})
|
||||
# FIXME: We don't currently require the gmock library to build the tests,
|
||||
# and it's likely we won't find it, so we don't try. As long as we've
|
||||
# found the gmock/gmock.h header and gtest_main that should be good enough.
|
||||
endif()
|
||||
endif()
|
||||
@@ -1,16 +0,0 @@
|
||||
include(FeatureSummary)
|
||||
|
||||
find_program(LLVMAR_EXECUTABLE
|
||||
NAMES llvm-ar
|
||||
DOC "The llvm-ar executable"
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(LLVMAr
|
||||
DEFAULT_MSG
|
||||
LLVMAR_EXECUTABLE)
|
||||
|
||||
SET_PACKAGE_PROPERTIES(LLVMAr PROPERTIES
|
||||
URL https://llvm.org/docs/CommandGuide/llvm-ar.html
|
||||
DESCRIPTION "create, modify, and extract from archives"
|
||||
)
|
||||
@@ -1,16 +0,0 @@
|
||||
include(FeatureSummary)
|
||||
|
||||
find_program(LLVMNM_EXECUTABLE
|
||||
NAMES llvm-nm
|
||||
DOC "The llvm-nm executable"
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(LLVMNm
|
||||
DEFAULT_MSG
|
||||
LLVMNM_EXECUTABLE)
|
||||
|
||||
SET_PACKAGE_PROPERTIES(LLVMNm PROPERTIES
|
||||
URL https://llvm.org/docs/CommandGuide/llvm-nm.html
|
||||
DESCRIPTION "list LLVM bitcode and object file’s symbol table"
|
||||
)
|
||||
@@ -1,15 +0,0 @@
|
||||
include(FeatureSummary)
|
||||
|
||||
find_program(LLVMRANLIB_EXECUTABLE
|
||||
NAMES llvm-ranlib
|
||||
DOC "The llvm-ranlib executable"
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(LLVMRanLib
|
||||
DEFAULT_MSG
|
||||
LLVMRANLIB_EXECUTABLE)
|
||||
|
||||
SET_PACKAGE_PROPERTIES(LLVMRanLib PROPERTIES
|
||||
DESCRIPTION "generate index for LLVM archive"
|
||||
)
|
||||
@@ -1,11 +0,0 @@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=${prefix}
|
||||
libdir=${prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: @PROJECT_NAME@
|
||||
Description: Google microbenchmark framework
|
||||
Version: @VERSION@
|
||||
|
||||
Libs: -L${libdir} -lbenchmark
|
||||
Cflags: -I${includedir}
|
||||
@@ -1,12 +0,0 @@
|
||||
#include <gnuregex.h>
|
||||
#include <string>
|
||||
int main() {
|
||||
std::string str = "test0159";
|
||||
regex_t re;
|
||||
int ec = regcomp(&re, "^[a-z]+[0-9]+$", REG_EXTENDED | REG_NOSUB);
|
||||
if (ec != 0) {
|
||||
return ec;
|
||||
}
|
||||
return regexec(&re, str.c_str(), 0, nullptr, 0) ? -1 : 0;
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
find_package(LLVMAr REQUIRED)
|
||||
set(CMAKE_AR "${LLVMAR_EXECUTABLE}" CACHE FILEPATH "" FORCE)
|
||||
|
||||
find_package(LLVMNm REQUIRED)
|
||||
set(CMAKE_NM "${LLVMNM_EXECUTABLE}" CACHE FILEPATH "" FORCE)
|
||||
|
||||
find_package(LLVMRanLib REQUIRED)
|
||||
set(CMAKE_RANLIB "${LLVMRANLIB_EXECUTABLE}" CACHE FILEPATH "" FORCE)
|
||||
@@ -1,14 +0,0 @@
|
||||
#include <regex.h>
|
||||
#include <string>
|
||||
int main() {
|
||||
std::string str = "test0159";
|
||||
regex_t re;
|
||||
int ec = regcomp(&re, "^[a-z]+[0-9]+$", REG_EXTENDED | REG_NOSUB);
|
||||
if (ec != 0) {
|
||||
return ec;
|
||||
}
|
||||
int ret = regexec(&re, str.c_str(), 0, nullptr, 0) ? -1 : 0;
|
||||
regfree(&re);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
macro(split_list listname)
|
||||
string(REPLACE ";" " " ${listname} "${${listname}}")
|
||||
endmacro()
|
||||
@@ -1,10 +0,0 @@
|
||||
#include <regex>
|
||||
#include <string>
|
||||
int main() {
|
||||
const std::string str = "test0159";
|
||||
std::regex re;
|
||||
re = std::regex("^[a-z]+[0-9]+$",
|
||||
std::regex_constants::extended | std::regex_constants::nosubs);
|
||||
return std::regex_search(str, re) ? 0 : -1;
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#include <chrono>
|
||||
|
||||
int main() {
|
||||
typedef std::chrono::steady_clock Clock;
|
||||
Clock::time_point tp = Clock::now();
|
||||
((void)tp);
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
#define HAVE_THREAD_SAFETY_ATTRIBUTES
|
||||
#include "../src/mutex.h"
|
||||
|
||||
int main() {}
|
||||
@@ -1,147 +0,0 @@
|
||||
# Assembly Tests
|
||||
|
||||
The Benchmark library provides a number of functions whose primary
|
||||
purpose in to affect assembly generation, including `DoNotOptimize`
|
||||
and `ClobberMemory`. In addition there are other functions,
|
||||
such as `KeepRunning`, for which generating good assembly is paramount.
|
||||
|
||||
For these functions it's important to have tests that verify the
|
||||
correctness and quality of the implementation. This requires testing
|
||||
the code generated by the compiler.
|
||||
|
||||
This document describes how the Benchmark library tests compiler output,
|
||||
as well as how to properly write new tests.
|
||||
|
||||
|
||||
## Anatomy of a Test
|
||||
|
||||
Writing a test has two steps:
|
||||
|
||||
* Write the code you want to generate assembly for.
|
||||
* Add `// CHECK` lines to match against the verified assembly.
|
||||
|
||||
Example:
|
||||
```c++
|
||||
|
||||
// CHECK-LABEL: test_add:
|
||||
extern "C" int test_add() {
|
||||
extern int ExternInt;
|
||||
return ExternInt + 1;
|
||||
|
||||
// CHECK: movl ExternInt(%rip), %eax
|
||||
// CHECK: addl %eax
|
||||
// CHECK: ret
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
#### LLVM Filecheck
|
||||
|
||||
[LLVM's Filecheck](https://llvm.org/docs/CommandGuide/FileCheck.html)
|
||||
is used to test the generated assembly against the `// CHECK` lines
|
||||
specified in the tests source file. Please see the documentation
|
||||
linked above for information on how to write `CHECK` directives.
|
||||
|
||||
#### Tips and Tricks:
|
||||
|
||||
* Tests should match the minimal amount of output required to establish
|
||||
correctness. `CHECK` directives don't have to match on the exact next line
|
||||
after the previous match, so tests should omit checks for unimportant
|
||||
bits of assembly. ([`CHECK-NEXT`](https://llvm.org/docs/CommandGuide/FileCheck.html#the-check-next-directive)
|
||||
can be used to ensure a match occurs exactly after the previous match).
|
||||
|
||||
* The tests are compiled with `-O3 -g0`. So we're only testing the
|
||||
optimized output.
|
||||
|
||||
* The assembly output is further cleaned up using `tools/strip_asm.py`.
|
||||
This removes comments, assembler directives, and unused labels before
|
||||
the test is run.
|
||||
|
||||
* The generated and stripped assembly file for a test is output under
|
||||
`<build-directory>/test/<test-name>.s`
|
||||
|
||||
* Filecheck supports using [`CHECK` prefixes](https://llvm.org/docs/CommandGuide/FileCheck.html#cmdoption-check-prefixes)
|
||||
to specify lines that should only match in certain situations.
|
||||
The Benchmark tests use `CHECK-CLANG` and `CHECK-GNU` for lines that
|
||||
are only expected to match Clang or GCC's output respectively. Normal
|
||||
`CHECK` lines match against all compilers. (Note: `CHECK-NOT` and
|
||||
`CHECK-LABEL` are NOT prefixes. They are versions of non-prefixed
|
||||
`CHECK` lines)
|
||||
|
||||
* Use `extern "C"` to disable name mangling for specific functions. This
|
||||
makes them easier to name in the `CHECK` lines.
|
||||
|
||||
|
||||
## Problems Writing Portable Tests
|
||||
|
||||
Writing tests which check the code generated by a compiler are
|
||||
inherently non-portable. Different compilers and even different compiler
|
||||
versions may generate entirely different code. The Benchmark tests
|
||||
must tolerate this.
|
||||
|
||||
LLVM Filecheck provides a number of mechanisms to help write
|
||||
"more portable" tests; including [matching using regular expressions](https://llvm.org/docs/CommandGuide/FileCheck.html#filecheck-pattern-matching-syntax),
|
||||
allowing the creation of [named variables](https://llvm.org/docs/CommandGuide/FileCheck.html#filecheck-variables)
|
||||
for later matching, and [checking non-sequential matches](https://llvm.org/docs/CommandGuide/FileCheck.html#the-check-dag-directive).
|
||||
|
||||
#### Capturing Variables
|
||||
|
||||
For example, say GCC stores a variable in a register but Clang stores
|
||||
it in memory. To write a test that tolerates both cases we "capture"
|
||||
the destination of the store, and then use the captured expression
|
||||
to write the remainder of the test.
|
||||
|
||||
```c++
|
||||
// CHECK-LABEL: test_div_no_op_into_shr:
|
||||
extern "C" void test_div_no_op_into_shr(int value) {
|
||||
int divisor = 2;
|
||||
benchmark::DoNotOptimize(divisor); // hide the value from the optimizer
|
||||
return value / divisor;
|
||||
|
||||
// CHECK: movl $2, [[DEST:.*]]
|
||||
// CHECK: idivl [[DEST]]
|
||||
// CHECK: ret
|
||||
}
|
||||
```
|
||||
|
||||
#### Using Regular Expressions to Match Differing Output
|
||||
|
||||
Often tests require testing assembly lines which may subtly differ
|
||||
between compilers or compiler versions. A common example of this
|
||||
is matching stack frame addresses. In this case regular expressions
|
||||
can be used to match the differing bits of output. For example:
|
||||
|
||||
```c++
|
||||
int ExternInt;
|
||||
struct Point { int x, y, z; };
|
||||
|
||||
// CHECK-LABEL: test_store_point:
|
||||
extern "C" void test_store_point() {
|
||||
Point p{ExternInt, ExternInt, ExternInt};
|
||||
benchmark::DoNotOptimize(p);
|
||||
|
||||
// CHECK: movl ExternInt(%rip), %eax
|
||||
// CHECK: movl %eax, -{{[0-9]+}}(%rsp)
|
||||
// CHECK: movl %eax, -{{[0-9]+}}(%rsp)
|
||||
// CHECK: movl %eax, -{{[0-9]+}}(%rsp)
|
||||
// CHECK: ret
|
||||
}
|
||||
```
|
||||
|
||||
## Current Requirements and Limitations
|
||||
|
||||
The tests require Filecheck to be installed along the `PATH` of the
|
||||
build machine. Otherwise the tests will be disabled.
|
||||
|
||||
Additionally, as mentioned in the previous section, codegen tests are
|
||||
inherently non-portable. Currently the tests are limited to:
|
||||
|
||||
* x86_64 targets.
|
||||
* Compiled with GCC or Clang
|
||||
|
||||
Further work could be done, at least on a limited basis, to extend the
|
||||
tests to other architectures and compilers (using `CHECK` prefixes).
|
||||
|
||||
Furthermore, the tests fail for builds which specify additional flags
|
||||
that modify code generation, including `--coverage` or `-fsanitize=`.
|
||||
|
||||
242
benchmarks/thirdparty/benchmark/docs/tools.md
vendored
242
benchmarks/thirdparty/benchmark/docs/tools.md
vendored
@@ -1,242 +0,0 @@
|
||||
# Benchmark Tools
|
||||
|
||||
## compare_bench.py
|
||||
|
||||
The `compare_bench.py` utility which can be used to compare the result of benchmarks.
|
||||
The program is invoked like:
|
||||
|
||||
``` bash
|
||||
$ compare_bench.py <old-benchmark> <new-benchmark> [benchmark options]...
|
||||
```
|
||||
|
||||
Where `<old-benchmark>` and `<new-benchmark>` either specify a benchmark executable file, or a JSON output file. The type of the input file is automatically detected. If a benchmark executable is specified then the benchmark is run to obtain the results. Otherwise the results are simply loaded from the output file.
|
||||
|
||||
`[benchmark options]` will be passed to the benchmarks invocations. They can be anything that binary accepts, be it either normal `--benchmark_*` parameters, or some custom parameters your binary takes.
|
||||
|
||||
The sample output using the JSON test files under `Inputs/` gives:
|
||||
|
||||
``` bash
|
||||
$ ./compare_bench.py ./gbench/Inputs/test1_run1.json ./gbench/Inputs/test1_run2.json
|
||||
Comparing ./gbench/Inputs/test1_run1.json to ./gbench/Inputs/test1_run2.json
|
||||
Benchmark Time CPU Time Old Time New CPU Old CPU New
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
BM_SameTimes +0.0000 +0.0000 10 10 10 10
|
||||
BM_2xFaster -0.5000 -0.5000 50 25 50 25
|
||||
BM_2xSlower +1.0000 +1.0000 50 100 50 100
|
||||
BM_1PercentFaster -0.0100 -0.0100 100 99 100 99
|
||||
BM_1PercentSlower +0.0100 +0.0100 100 101 100 101
|
||||
BM_10PercentFaster -0.1000 -0.1000 100 90 100 90
|
||||
BM_10PercentSlower +0.1000 +0.1000 100 110 100 110
|
||||
BM_100xSlower +99.0000 +99.0000 100 10000 100 10000
|
||||
BM_100xFaster -0.9900 -0.9900 10000 100 10000 100
|
||||
BM_10PercentCPUToTime +0.1000 -0.1000 100 110 100 90
|
||||
BM_ThirdFaster -0.3333 -0.3334 100 67 100 67
|
||||
BM_BadTimeUnit -0.9000 +0.2000 0 0 0 1
|
||||
```
|
||||
|
||||
As you can note, the values in `Time` and `CPU` columns are calculated as `(new - old) / |old|`.
|
||||
|
||||
When a benchmark executable is run, the raw output from the benchmark is printed in real time to stdout. The sample output using `benchmark/basic_test` for both arguments looks like:
|
||||
|
||||
```
|
||||
./compare_bench.py test/basic_test test/basic_test --benchmark_filter=BM_empty.*
|
||||
RUNNING: test/basic_test --benchmark_filter=BM_empty.* --benchmark_out=/tmp/tmpN7LF3a
|
||||
Run on (8 X 4000 MHz CPU s)
|
||||
2017-11-07 23:28:36
|
||||
---------------------------------------------------------------------
|
||||
Benchmark Time CPU Iterations
|
||||
---------------------------------------------------------------------
|
||||
BM_empty 4 ns 4 ns 170178757
|
||||
BM_empty/threads:8 1 ns 7 ns 103868920
|
||||
BM_empty_stop_start 0 ns 0 ns 1000000000
|
||||
BM_empty_stop_start/threads:8 0 ns 0 ns 1403031720
|
||||
RUNNING: /test/basic_test --benchmark_filter=BM_empty.* --benchmark_out=/tmp/tmplvrIp8
|
||||
Run on (8 X 4000 MHz CPU s)
|
||||
2017-11-07 23:28:38
|
||||
---------------------------------------------------------------------
|
||||
Benchmark Time CPU Iterations
|
||||
---------------------------------------------------------------------
|
||||
BM_empty 4 ns 4 ns 169534855
|
||||
BM_empty/threads:8 1 ns 7 ns 104188776
|
||||
BM_empty_stop_start 0 ns 0 ns 1000000000
|
||||
BM_empty_stop_start/threads:8 0 ns 0 ns 1404159424
|
||||
Comparing ../build/test/basic_test to ../build/test/basic_test
|
||||
Benchmark Time CPU Time Old Time New CPU Old CPU New
|
||||
---------------------------------------------------------------------------------------------------------------------
|
||||
BM_empty -0.0048 -0.0049 4 4 4 4
|
||||
BM_empty/threads:8 -0.0123 -0.0054 1 1 7 7
|
||||
BM_empty_stop_start -0.0000 -0.0000 0 0 0 0
|
||||
BM_empty_stop_start/threads:8 -0.0029 +0.0001 0 0 0 0
|
||||
|
||||
```
|
||||
|
||||
As you can note, the values in `Time` and `CPU` columns are calculated as `(new - old) / |old|`.
|
||||
Obviously this example doesn't give any useful output, but it's intended to show the output format when 'compare_bench.py' needs to run benchmarks.
|
||||
|
||||
## compare.py
|
||||
|
||||
The `compare.py` can be used to compare the result of benchmarks.
|
||||
There are three modes of operation:
|
||||
|
||||
1. Just compare two benchmarks, what `compare_bench.py` did.
|
||||
The program is invoked like:
|
||||
|
||||
``` bash
|
||||
$ compare.py benchmarks <benchmark_baseline> <benchmark_contender> [benchmark options]...
|
||||
```
|
||||
Where `<benchmark_baseline>` and `<benchmark_contender>` either specify a benchmark executable file, or a JSON output file. The type of the input file is automatically detected. If a benchmark executable is specified then the benchmark is run to obtain the results. Otherwise the results are simply loaded from the output file.
|
||||
|
||||
`[benchmark options]` will be passed to the benchmarks invocations. They can be anything that binary accepts, be it either normal `--benchmark_*` parameters, or some custom parameters your binary takes.
|
||||
|
||||
Example output:
|
||||
```
|
||||
$ ./compare.py benchmarks ./a.out ./a.out
|
||||
RUNNING: ./a.out --benchmark_out=/tmp/tmprBT5nW
|
||||
Run on (8 X 4000 MHz CPU s)
|
||||
2017-11-07 21:16:44
|
||||
------------------------------------------------------
|
||||
Benchmark Time CPU Iterations
|
||||
------------------------------------------------------
|
||||
BM_memcpy/8 36 ns 36 ns 19101577 211.669MB/s
|
||||
BM_memcpy/64 76 ns 76 ns 9412571 800.199MB/s
|
||||
BM_memcpy/512 84 ns 84 ns 8249070 5.64771GB/s
|
||||
BM_memcpy/1024 116 ns 116 ns 6181763 8.19505GB/s
|
||||
BM_memcpy/8192 643 ns 643 ns 1062855 11.8636GB/s
|
||||
BM_copy/8 222 ns 222 ns 3137987 34.3772MB/s
|
||||
BM_copy/64 1608 ns 1608 ns 432758 37.9501MB/s
|
||||
BM_copy/512 12589 ns 12589 ns 54806 38.7867MB/s
|
||||
BM_copy/1024 25169 ns 25169 ns 27713 38.8003MB/s
|
||||
BM_copy/8192 201165 ns 201112 ns 3486 38.8466MB/s
|
||||
RUNNING: ./a.out --benchmark_out=/tmp/tmpt1wwG_
|
||||
Run on (8 X 4000 MHz CPU s)
|
||||
2017-11-07 21:16:53
|
||||
------------------------------------------------------
|
||||
Benchmark Time CPU Iterations
|
||||
------------------------------------------------------
|
||||
BM_memcpy/8 36 ns 36 ns 19397903 211.255MB/s
|
||||
BM_memcpy/64 73 ns 73 ns 9691174 839.635MB/s
|
||||
BM_memcpy/512 85 ns 85 ns 8312329 5.60101GB/s
|
||||
BM_memcpy/1024 118 ns 118 ns 6438774 8.11608GB/s
|
||||
BM_memcpy/8192 656 ns 656 ns 1068644 11.6277GB/s
|
||||
BM_copy/8 223 ns 223 ns 3146977 34.2338MB/s
|
||||
BM_copy/64 1611 ns 1611 ns 435340 37.8751MB/s
|
||||
BM_copy/512 12622 ns 12622 ns 54818 38.6844MB/s
|
||||
BM_copy/1024 25257 ns 25239 ns 27779 38.6927MB/s
|
||||
BM_copy/8192 205013 ns 205010 ns 3479 38.108MB/s
|
||||
Comparing ./a.out to ./a.out
|
||||
Benchmark Time CPU Time Old Time New CPU Old CPU New
|
||||
------------------------------------------------------------------------------------------------------
|
||||
BM_memcpy/8 +0.0020 +0.0020 36 36 36 36
|
||||
BM_memcpy/64 -0.0468 -0.0470 76 73 76 73
|
||||
BM_memcpy/512 +0.0081 +0.0083 84 85 84 85
|
||||
BM_memcpy/1024 +0.0098 +0.0097 116 118 116 118
|
||||
BM_memcpy/8192 +0.0200 +0.0203 643 656 643 656
|
||||
BM_copy/8 +0.0046 +0.0042 222 223 222 223
|
||||
BM_copy/64 +0.0020 +0.0020 1608 1611 1608 1611
|
||||
BM_copy/512 +0.0027 +0.0026 12589 12622 12589 12622
|
||||
BM_copy/1024 +0.0035 +0.0028 25169 25257 25169 25239
|
||||
BM_copy/8192 +0.0191 +0.0194 201165 205013 201112 205010
|
||||
```
|
||||
|
||||
What it does is for the every benchmark from the first run it looks for the benchmark with exactly the same name in the second run, and then compares the results. If the names differ, the benchmark is omitted from the diff.
|
||||
As you can note, the values in `Time` and `CPU` columns are calculated as `(new - old) / |old|`.
|
||||
|
||||
2. Compare two different filters of one benchmark
|
||||
The program is invoked like:
|
||||
|
||||
``` bash
|
||||
$ compare.py filters <benchmark> <filter_baseline> <filter_contender> [benchmark options]...
|
||||
```
|
||||
Where `<benchmark>` either specify a benchmark executable file, or a JSON output file. The type of the input file is automatically detected. If a benchmark executable is specified then the benchmark is run to obtain the results. Otherwise the results are simply loaded from the output file.
|
||||
|
||||
Where `<filter_baseline>` and `<filter_contender>` are the same regex filters that you would pass to the `[--benchmark_filter=<regex>]` parameter of the benchmark binary.
|
||||
|
||||
`[benchmark options]` will be passed to the benchmarks invocations. They can be anything that binary accepts, be it either normal `--benchmark_*` parameters, or some custom parameters your binary takes.
|
||||
|
||||
Example output:
|
||||
```
|
||||
$ ./compare.py filters ./a.out BM_memcpy BM_copy
|
||||
RUNNING: ./a.out --benchmark_filter=BM_memcpy --benchmark_out=/tmp/tmpBWKk0k
|
||||
Run on (8 X 4000 MHz CPU s)
|
||||
2017-11-07 21:37:28
|
||||
------------------------------------------------------
|
||||
Benchmark Time CPU Iterations
|
||||
------------------------------------------------------
|
||||
BM_memcpy/8 36 ns 36 ns 17891491 211.215MB/s
|
||||
BM_memcpy/64 74 ns 74 ns 9400999 825.646MB/s
|
||||
BM_memcpy/512 87 ns 87 ns 8027453 5.46126GB/s
|
||||
BM_memcpy/1024 111 ns 111 ns 6116853 8.5648GB/s
|
||||
BM_memcpy/8192 657 ns 656 ns 1064679 11.6247GB/s
|
||||
RUNNING: ./a.out --benchmark_filter=BM_copy --benchmark_out=/tmp/tmpAvWcOM
|
||||
Run on (8 X 4000 MHz CPU s)
|
||||
2017-11-07 21:37:33
|
||||
----------------------------------------------------
|
||||
Benchmark Time CPU Iterations
|
||||
----------------------------------------------------
|
||||
BM_copy/8 227 ns 227 ns 3038700 33.6264MB/s
|
||||
BM_copy/64 1640 ns 1640 ns 426893 37.2154MB/s
|
||||
BM_copy/512 12804 ns 12801 ns 55417 38.1444MB/s
|
||||
BM_copy/1024 25409 ns 25407 ns 27516 38.4365MB/s
|
||||
BM_copy/8192 202986 ns 202990 ns 3454 38.4871MB/s
|
||||
Comparing BM_memcpy to BM_copy (from ./a.out)
|
||||
Benchmark Time CPU Time Old Time New CPU Old CPU New
|
||||
--------------------------------------------------------------------------------------------------------------------
|
||||
[BM_memcpy vs. BM_copy]/8 +5.2829 +5.2812 36 227 36 227
|
||||
[BM_memcpy vs. BM_copy]/64 +21.1719 +21.1856 74 1640 74 1640
|
||||
[BM_memcpy vs. BM_copy]/512 +145.6487 +145.6097 87 12804 87 12801
|
||||
[BM_memcpy vs. BM_copy]/1024 +227.1860 +227.1776 111 25409 111 25407
|
||||
[BM_memcpy vs. BM_copy]/8192 +308.1664 +308.2898 657 202986 656 202990
|
||||
```
|
||||
|
||||
As you can see, it applies filter to the benchmarks, both when running the benchmark, and before doing the diff. And to make the diff work, the matches are replaced with some common string. Thus, you can compare two different benchmark families within one benchmark binary.
|
||||
As you can note, the values in `Time` and `CPU` columns are calculated as `(new - old) / |old|`.
|
||||
|
||||
3. Compare filter one from benchmark one to filter two from benchmark two:
|
||||
The program is invoked like:
|
||||
|
||||
``` bash
|
||||
$ compare.py filters <benchmark_baseline> <filter_baseline> <benchmark_contender> <filter_contender> [benchmark options]...
|
||||
```
|
||||
|
||||
Where `<benchmark_baseline>` and `<benchmark_contender>` either specify a benchmark executable file, or a JSON output file. The type of the input file is automatically detected. If a benchmark executable is specified then the benchmark is run to obtain the results. Otherwise the results are simply loaded from the output file.
|
||||
|
||||
Where `<filter_baseline>` and `<filter_contender>` are the same regex filters that you would pass to the `[--benchmark_filter=<regex>]` parameter of the benchmark binary.
|
||||
|
||||
`[benchmark options]` will be passed to the benchmarks invocations. They can be anything that binary accepts, be it either normal `--benchmark_*` parameters, or some custom parameters your binary takes.
|
||||
|
||||
Example output:
|
||||
```
|
||||
$ ./compare.py benchmarksfiltered ./a.out BM_memcpy ./a.out BM_copy
|
||||
RUNNING: ./a.out --benchmark_filter=BM_memcpy --benchmark_out=/tmp/tmp_FvbYg
|
||||
Run on (8 X 4000 MHz CPU s)
|
||||
2017-11-07 21:38:27
|
||||
------------------------------------------------------
|
||||
Benchmark Time CPU Iterations
|
||||
------------------------------------------------------
|
||||
BM_memcpy/8 37 ns 37 ns 18953482 204.118MB/s
|
||||
BM_memcpy/64 74 ns 74 ns 9206578 828.245MB/s
|
||||
BM_memcpy/512 91 ns 91 ns 8086195 5.25476GB/s
|
||||
BM_memcpy/1024 120 ns 120 ns 5804513 7.95662GB/s
|
||||
BM_memcpy/8192 664 ns 664 ns 1028363 11.4948GB/s
|
||||
RUNNING: ./a.out --benchmark_filter=BM_copy --benchmark_out=/tmp/tmpDfL5iE
|
||||
Run on (8 X 4000 MHz CPU s)
|
||||
2017-11-07 21:38:32
|
||||
----------------------------------------------------
|
||||
Benchmark Time CPU Iterations
|
||||
----------------------------------------------------
|
||||
BM_copy/8 230 ns 230 ns 2985909 33.1161MB/s
|
||||
BM_copy/64 1654 ns 1653 ns 419408 36.9137MB/s
|
||||
BM_copy/512 13122 ns 13120 ns 53403 37.2156MB/s
|
||||
BM_copy/1024 26679 ns 26666 ns 26575 36.6218MB/s
|
||||
BM_copy/8192 215068 ns 215053 ns 3221 36.3283MB/s
|
||||
Comparing BM_memcpy (from ./a.out) to BM_copy (from ./a.out)
|
||||
Benchmark Time CPU Time Old Time New CPU Old CPU New
|
||||
--------------------------------------------------------------------------------------------------------------------
|
||||
[BM_memcpy vs. BM_copy]/8 +5.1649 +5.1637 37 230 37 230
|
||||
[BM_memcpy vs. BM_copy]/64 +21.4352 +21.4374 74 1654 74 1653
|
||||
[BM_memcpy vs. BM_copy]/512 +143.6022 +143.5865 91 13122 91 13120
|
||||
[BM_memcpy vs. BM_copy]/1024 +221.5903 +221.4790 120 26679 120 26666
|
||||
[BM_memcpy vs. BM_copy]/8192 +322.9059 +323.0096 664 215068 664 215053
|
||||
```
|
||||
This is a mix of the previous two modes, two (potentially different) benchmark binaries are run, and a different filter is applied to each one.
|
||||
As you can note, the values in `Time` and `CPU` columns are calculated as `(new - old) / |old|`.
|
||||
File diff suppressed because it is too large
Load Diff
320
benchmarks/thirdparty/benchmark/mingw.py
vendored
320
benchmarks/thirdparty/benchmark/mingw.py
vendored
@@ -1,320 +0,0 @@
|
||||
#! /usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
import argparse
|
||||
import errno
|
||||
import logging
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
import sys
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
try:
|
||||
import winreg
|
||||
except ImportError:
|
||||
import _winreg as winreg
|
||||
try:
|
||||
import urllib.request as request
|
||||
except ImportError:
|
||||
import urllib as request
|
||||
try:
|
||||
import urllib.parse as parse
|
||||
except ImportError:
|
||||
import urlparse as parse
|
||||
|
||||
class EmptyLogger(object):
|
||||
'''
|
||||
Provides an implementation that performs no logging
|
||||
'''
|
||||
def debug(self, *k, **kw):
|
||||
pass
|
||||
def info(self, *k, **kw):
|
||||
pass
|
||||
def warn(self, *k, **kw):
|
||||
pass
|
||||
def error(self, *k, **kw):
|
||||
pass
|
||||
def critical(self, *k, **kw):
|
||||
pass
|
||||
def setLevel(self, *k, **kw):
|
||||
pass
|
||||
|
||||
urls = (
|
||||
'http://downloads.sourceforge.net/project/mingw-w64/Toolchains%20'
|
||||
'targetting%20Win32/Personal%20Builds/mingw-builds/installer/'
|
||||
'repository.txt',
|
||||
'http://downloads.sourceforge.net/project/mingwbuilds/host-windows/'
|
||||
'repository.txt'
|
||||
)
|
||||
'''
|
||||
A list of mingw-build repositories
|
||||
'''
|
||||
|
||||
def repository(urls = urls, log = EmptyLogger()):
|
||||
'''
|
||||
Downloads and parse mingw-build repository files and parses them
|
||||
'''
|
||||
log.info('getting mingw-builds repository')
|
||||
versions = {}
|
||||
re_sourceforge = re.compile(r'http://sourceforge.net/projects/([^/]+)/files')
|
||||
re_sub = r'http://downloads.sourceforge.net/project/\1'
|
||||
for url in urls:
|
||||
log.debug(' - requesting: %s', url)
|
||||
socket = request.urlopen(url)
|
||||
repo = socket.read()
|
||||
if not isinstance(repo, str):
|
||||
repo = repo.decode();
|
||||
socket.close()
|
||||
for entry in repo.split('\n')[:-1]:
|
||||
value = entry.split('|')
|
||||
version = tuple([int(n) for n in value[0].strip().split('.')])
|
||||
version = versions.setdefault(version, {})
|
||||
arch = value[1].strip()
|
||||
if arch == 'x32':
|
||||
arch = 'i686'
|
||||
elif arch == 'x64':
|
||||
arch = 'x86_64'
|
||||
arch = version.setdefault(arch, {})
|
||||
threading = arch.setdefault(value[2].strip(), {})
|
||||
exceptions = threading.setdefault(value[3].strip(), {})
|
||||
revision = exceptions.setdefault(int(value[4].strip()[3:]),
|
||||
re_sourceforge.sub(re_sub, value[5].strip()))
|
||||
return versions
|
||||
|
||||
def find_in_path(file, path=None):
|
||||
'''
|
||||
Attempts to find an executable in the path
|
||||
'''
|
||||
if platform.system() == 'Windows':
|
||||
file += '.exe'
|
||||
if path is None:
|
||||
path = os.environ.get('PATH', '')
|
||||
if type(path) is type(''):
|
||||
path = path.split(os.pathsep)
|
||||
return list(filter(os.path.exists,
|
||||
map(lambda dir, file=file: os.path.join(dir, file), path)))
|
||||
|
||||
def find_7zip(log = EmptyLogger()):
|
||||
'''
|
||||
Attempts to find 7zip for unpacking the mingw-build archives
|
||||
'''
|
||||
log.info('finding 7zip')
|
||||
path = find_in_path('7z')
|
||||
if not path:
|
||||
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r'SOFTWARE\7-Zip')
|
||||
path, _ = winreg.QueryValueEx(key, 'Path')
|
||||
path = [os.path.join(path, '7z.exe')]
|
||||
log.debug('found \'%s\'', path[0])
|
||||
return path[0]
|
||||
|
||||
find_7zip()
|
||||
|
||||
def unpack(archive, location, log = EmptyLogger()):
|
||||
'''
|
||||
Unpacks a mingw-builds archive
|
||||
'''
|
||||
sevenzip = find_7zip(log)
|
||||
log.info('unpacking %s', os.path.basename(archive))
|
||||
cmd = [sevenzip, 'x', archive, '-o' + location, '-y']
|
||||
log.debug(' - %r', cmd)
|
||||
with open(os.devnull, 'w') as devnull:
|
||||
subprocess.check_call(cmd, stdout = devnull)
|
||||
|
||||
def download(url, location, log = EmptyLogger()):
|
||||
'''
|
||||
Downloads and unpacks a mingw-builds archive
|
||||
'''
|
||||
log.info('downloading MinGW')
|
||||
log.debug(' - url: %s', url)
|
||||
log.debug(' - location: %s', location)
|
||||
|
||||
re_content = re.compile(r'attachment;[ \t]*filename=(")?([^"]*)(")?[\r\n]*')
|
||||
|
||||
stream = request.urlopen(url)
|
||||
try:
|
||||
content = stream.getheader('Content-Disposition') or ''
|
||||
except AttributeError:
|
||||
content = stream.headers.getheader('Content-Disposition') or ''
|
||||
matches = re_content.match(content)
|
||||
if matches:
|
||||
filename = matches.group(2)
|
||||
else:
|
||||
parsed = parse.urlparse(stream.geturl())
|
||||
filename = os.path.basename(parsed.path)
|
||||
|
||||
try:
|
||||
os.makedirs(location)
|
||||
except OSError as e:
|
||||
if e.errno == errno.EEXIST and os.path.isdir(location):
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
|
||||
archive = os.path.join(location, filename)
|
||||
with open(archive, 'wb') as out:
|
||||
while True:
|
||||
buf = stream.read(1024)
|
||||
if not buf:
|
||||
break
|
||||
out.write(buf)
|
||||
unpack(archive, location, log = log)
|
||||
os.remove(archive)
|
||||
|
||||
possible = os.path.join(location, 'mingw64')
|
||||
if not os.path.exists(possible):
|
||||
possible = os.path.join(location, 'mingw32')
|
||||
if not os.path.exists(possible):
|
||||
raise ValueError('Failed to find unpacked MinGW: ' + possible)
|
||||
return possible
|
||||
|
||||
def root(location = None, arch = None, version = None, threading = None,
|
||||
exceptions = None, revision = None, log = EmptyLogger()):
|
||||
'''
|
||||
Returns the root folder of a specific version of the mingw-builds variant
|
||||
of gcc. Will download the compiler if needed
|
||||
'''
|
||||
|
||||
# Get the repository if we don't have all the information
|
||||
if not (arch and version and threading and exceptions and revision):
|
||||
versions = repository(log = log)
|
||||
|
||||
# Determine some defaults
|
||||
version = version or max(versions.keys())
|
||||
if not arch:
|
||||
arch = platform.machine().lower()
|
||||
if arch == 'x86':
|
||||
arch = 'i686'
|
||||
elif arch == 'amd64':
|
||||
arch = 'x86_64'
|
||||
if not threading:
|
||||
keys = versions[version][arch].keys()
|
||||
if 'posix' in keys:
|
||||
threading = 'posix'
|
||||
elif 'win32' in keys:
|
||||
threading = 'win32'
|
||||
else:
|
||||
threading = keys[0]
|
||||
if not exceptions:
|
||||
keys = versions[version][arch][threading].keys()
|
||||
if 'seh' in keys:
|
||||
exceptions = 'seh'
|
||||
elif 'sjlj' in keys:
|
||||
exceptions = 'sjlj'
|
||||
else:
|
||||
exceptions = keys[0]
|
||||
if revision == None:
|
||||
revision = max(versions[version][arch][threading][exceptions].keys())
|
||||
if not location:
|
||||
location = os.path.join(tempfile.gettempdir(), 'mingw-builds')
|
||||
|
||||
# Get the download url
|
||||
url = versions[version][arch][threading][exceptions][revision]
|
||||
|
||||
# Tell the user whatzzup
|
||||
log.info('finding MinGW %s', '.'.join(str(v) for v in version))
|
||||
log.debug(' - arch: %s', arch)
|
||||
log.debug(' - threading: %s', threading)
|
||||
log.debug(' - exceptions: %s', exceptions)
|
||||
log.debug(' - revision: %s', revision)
|
||||
log.debug(' - url: %s', url)
|
||||
|
||||
# Store each specific revision differently
|
||||
slug = '{version}-{arch}-{threading}-{exceptions}-rev{revision}'
|
||||
slug = slug.format(
|
||||
version = '.'.join(str(v) for v in version),
|
||||
arch = arch,
|
||||
threading = threading,
|
||||
exceptions = exceptions,
|
||||
revision = revision
|
||||
)
|
||||
if arch == 'x86_64':
|
||||
root_dir = os.path.join(location, slug, 'mingw64')
|
||||
elif arch == 'i686':
|
||||
root_dir = os.path.join(location, slug, 'mingw32')
|
||||
else:
|
||||
raise ValueError('Unknown MinGW arch: ' + arch)
|
||||
|
||||
# Download if needed
|
||||
if not os.path.exists(root_dir):
|
||||
downloaded = download(url, os.path.join(location, slug), log = log)
|
||||
if downloaded != root_dir:
|
||||
raise ValueError('The location of mingw did not match\n%s\n%s'
|
||||
% (downloaded, root_dir))
|
||||
|
||||
return root_dir
|
||||
|
||||
def str2ver(string):
|
||||
'''
|
||||
Converts a version string into a tuple
|
||||
'''
|
||||
try:
|
||||
version = tuple(int(v) for v in string.split('.'))
|
||||
if len(version) is not 3:
|
||||
raise ValueError()
|
||||
except ValueError:
|
||||
raise argparse.ArgumentTypeError(
|
||||
'please provide a three digit version string')
|
||||
return version
|
||||
|
||||
def main():
|
||||
'''
|
||||
Invoked when the script is run directly by the python interpreter
|
||||
'''
|
||||
parser = argparse.ArgumentParser(
|
||||
description = 'Downloads a specific version of MinGW',
|
||||
formatter_class = argparse.ArgumentDefaultsHelpFormatter
|
||||
)
|
||||
parser.add_argument('--location',
|
||||
help = 'the location to download the compiler to',
|
||||
default = os.path.join(tempfile.gettempdir(), 'mingw-builds'))
|
||||
parser.add_argument('--arch', required = True, choices = ['i686', 'x86_64'],
|
||||
help = 'the target MinGW architecture string')
|
||||
parser.add_argument('--version', type = str2ver,
|
||||
help = 'the version of GCC to download')
|
||||
parser.add_argument('--threading', choices = ['posix', 'win32'],
|
||||
help = 'the threading type of the compiler')
|
||||
parser.add_argument('--exceptions', choices = ['sjlj', 'seh', 'dwarf'],
|
||||
help = 'the method to throw exceptions')
|
||||
parser.add_argument('--revision', type=int,
|
||||
help = 'the revision of the MinGW release')
|
||||
group = parser.add_mutually_exclusive_group()
|
||||
group.add_argument('-v', '--verbose', action='store_true',
|
||||
help='increase the script output verbosity')
|
||||
group.add_argument('-q', '--quiet', action='store_true',
|
||||
help='only print errors and warning')
|
||||
args = parser.parse_args()
|
||||
|
||||
# Create the logger
|
||||
logger = logging.getLogger('mingw')
|
||||
handler = logging.StreamHandler()
|
||||
formatter = logging.Formatter('%(message)s')
|
||||
handler.setFormatter(formatter)
|
||||
logger.addHandler(handler)
|
||||
logger.setLevel(logging.INFO)
|
||||
if args.quiet:
|
||||
logger.setLevel(logging.WARN)
|
||||
if args.verbose:
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
# Get MinGW
|
||||
root_dir = root(location = args.location, arch = args.arch,
|
||||
version = args.version, threading = args.threading,
|
||||
exceptions = args.exceptions, revision = args.revision,
|
||||
log = logger)
|
||||
|
||||
sys.stdout.write('%s\n' % os.path.join(root_dir, 'bin'))
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
main()
|
||||
except IOError as e:
|
||||
sys.stderr.write('IO error: %s\n' % e)
|
||||
sys.exit(1)
|
||||
except OSError as e:
|
||||
sys.stderr.write('OS error: %s\n' % e)
|
||||
sys.exit(1)
|
||||
except KeyboardInterrupt as e:
|
||||
sys.stderr.write('Killed\n')
|
||||
sys.exit(1)
|
||||
16
benchmarks/thirdparty/benchmark/releasing.md
vendored
16
benchmarks/thirdparty/benchmark/releasing.md
vendored
@@ -1,16 +0,0 @@
|
||||
# How to release
|
||||
|
||||
* Make sure you're on master and synced to HEAD
|
||||
* Ensure the project builds and tests run (sanity check only, obviously)
|
||||
* `parallel -j0 exec ::: test/*_test` can help ensure everything at least
|
||||
passes
|
||||
* Prepare release notes
|
||||
* `git log $(git describe --abbrev=0 --tags)..HEAD` gives you the list of
|
||||
commits between the last annotated tag and HEAD
|
||||
* Pick the most interesting.
|
||||
* Create a release through github's interface
|
||||
* Note this will create a lightweight tag.
|
||||
* Update this to an annotated tag:
|
||||
* `git pull --tags`
|
||||
* `git tag -a -f <tag> <tag>`
|
||||
* `git push --force origin`
|
||||
105
benchmarks/thirdparty/benchmark/src/CMakeLists.txt
vendored
105
benchmarks/thirdparty/benchmark/src/CMakeLists.txt
vendored
@@ -1,105 +0,0 @@
|
||||
# Allow the source files to find headers in src/
|
||||
include_directories(${PROJECT_SOURCE_DIR}/src)
|
||||
|
||||
if (DEFINED BENCHMARK_CXX_LINKER_FLAGS)
|
||||
list(APPEND CMAKE_SHARED_LINKER_FLAGS ${BENCHMARK_CXX_LINKER_FLAGS})
|
||||
list(APPEND CMAKE_MODULE_LINKER_FLAGS ${BENCHMARK_CXX_LINKER_FLAGS})
|
||||
endif()
|
||||
|
||||
file(GLOB
|
||||
SOURCE_FILES
|
||||
*.cc
|
||||
${PROJECT_SOURCE_DIR}/include/benchmark/*.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/*.h)
|
||||
list(FILTER SOURCE_FILES EXCLUDE REGEX "benchmark_main\\.cc")
|
||||
|
||||
add_library(benchmark ${SOURCE_FILES})
|
||||
set_target_properties(benchmark PROPERTIES
|
||||
OUTPUT_NAME "benchmark"
|
||||
VERSION ${GENERIC_LIB_VERSION}
|
||||
SOVERSION ${GENERIC_LIB_SOVERSION}
|
||||
)
|
||||
target_include_directories(benchmark PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
|
||||
)
|
||||
|
||||
# Link threads.
|
||||
target_link_libraries(benchmark ${BENCHMARK_CXX_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
find_library(LIBRT rt)
|
||||
if(LIBRT)
|
||||
target_link_libraries(benchmark ${LIBRT})
|
||||
endif()
|
||||
|
||||
# We need extra libraries on Windows
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||
target_link_libraries(benchmark Shlwapi)
|
||||
endif()
|
||||
|
||||
# We need extra libraries on Solaris
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
|
||||
target_link_libraries(benchmark kstat)
|
||||
endif()
|
||||
|
||||
# Benchmark main library
|
||||
add_library(benchmark_main "benchmark_main.cc")
|
||||
set_target_properties(benchmark_main PROPERTIES
|
||||
OUTPUT_NAME "benchmark_main"
|
||||
VERSION ${GENERIC_LIB_VERSION}
|
||||
SOVERSION ${GENERIC_LIB_SOVERSION}
|
||||
)
|
||||
target_include_directories(benchmark PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
|
||||
)
|
||||
target_link_libraries(benchmark_main benchmark)
|
||||
|
||||
set(include_install_dir "include")
|
||||
set(lib_install_dir "lib/")
|
||||
set(bin_install_dir "bin/")
|
||||
set(config_install_dir "lib/cmake/${PROJECT_NAME}")
|
||||
set(pkgconfig_install_dir "lib/pkgconfig")
|
||||
|
||||
set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated")
|
||||
|
||||
set(version_config "${generated_dir}/${PROJECT_NAME}ConfigVersion.cmake")
|
||||
set(project_config "${generated_dir}/${PROJECT_NAME}Config.cmake")
|
||||
set(pkg_config "${generated_dir}/${PROJECT_NAME}.pc")
|
||||
set(targets_export_name "${PROJECT_NAME}Targets")
|
||||
|
||||
set(namespace "${PROJECT_NAME}::")
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
write_basic_package_version_file(
|
||||
"${version_config}" VERSION ${GIT_VERSION} COMPATIBILITY SameMajorVersion
|
||||
)
|
||||
|
||||
configure_file("${PROJECT_SOURCE_DIR}/cmake/Config.cmake.in" "${project_config}" @ONLY)
|
||||
configure_file("${PROJECT_SOURCE_DIR}/cmake/benchmark.pc.in" "${pkg_config}" @ONLY)
|
||||
|
||||
if (BENCHMARK_ENABLE_INSTALL)
|
||||
# Install target (will install the library to specified CMAKE_INSTALL_PREFIX variable)
|
||||
install(
|
||||
TARGETS benchmark benchmark_main
|
||||
EXPORT ${targets_export_name}
|
||||
ARCHIVE DESTINATION ${lib_install_dir}
|
||||
LIBRARY DESTINATION ${lib_install_dir}
|
||||
RUNTIME DESTINATION ${bin_install_dir}
|
||||
INCLUDES DESTINATION ${include_install_dir})
|
||||
|
||||
install(
|
||||
DIRECTORY "${PROJECT_SOURCE_DIR}/include/benchmark"
|
||||
DESTINATION ${include_install_dir}
|
||||
FILES_MATCHING PATTERN "*.*h")
|
||||
|
||||
install(
|
||||
FILES "${project_config}" "${version_config}"
|
||||
DESTINATION "${config_install_dir}")
|
||||
|
||||
install(
|
||||
FILES "${pkg_config}"
|
||||
DESTINATION "${pkgconfig_install_dir}")
|
||||
|
||||
install(
|
||||
EXPORT "${targets_export_name}"
|
||||
NAMESPACE "${namespace}"
|
||||
DESTINATION "${config_install_dir}")
|
||||
endif()
|
||||
33
benchmarks/thirdparty/benchmark/src/arraysize.h
vendored
33
benchmarks/thirdparty/benchmark/src/arraysize.h
vendored
@@ -1,33 +0,0 @@
|
||||
#ifndef BENCHMARK_ARRAYSIZE_H_
|
||||
#define BENCHMARK_ARRAYSIZE_H_
|
||||
|
||||
#include "internal_macros.h"
|
||||
|
||||
namespace benchmark {
|
||||
namespace internal {
|
||||
// The arraysize(arr) macro returns the # of elements in an array arr.
|
||||
// The expression is a compile-time constant, and therefore can be
|
||||
// used in defining new arrays, for example. If you use arraysize on
|
||||
// a pointer by mistake, you will get a compile-time error.
|
||||
//
|
||||
|
||||
// This template function declaration is used in defining arraysize.
|
||||
// Note that the function doesn't need an implementation, as we only
|
||||
// use its type.
|
||||
template <typename T, size_t N>
|
||||
char (&ArraySizeHelper(T (&array)[N]))[N];
|
||||
|
||||
// That gcc wants both of these prototypes seems mysterious. VC, for
|
||||
// its part, can't decide which to use (another mystery). Matching of
|
||||
// template overloads: the final frontier.
|
||||
#ifndef COMPILER_MSVC
|
||||
template <typename T, size_t N>
|
||||
char (&ArraySizeHelper(const T (&array)[N]))[N];
|
||||
#endif
|
||||
|
||||
#define arraysize(array) (sizeof(::benchmark::internal::ArraySizeHelper(array)))
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace benchmark
|
||||
|
||||
#endif // BENCHMARK_ARRAYSIZE_H_
|
||||
630
benchmarks/thirdparty/benchmark/src/benchmark.cc
vendored
630
benchmarks/thirdparty/benchmark/src/benchmark.cc
vendored
@@ -1,630 +0,0 @@
|
||||
// Copyright 2015 Google Inc. All rights reserved.
|
||||
//
|
||||
// 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 "benchmark/benchmark.h"
|
||||
#include "benchmark_api_internal.h"
|
||||
#include "internal_macros.h"
|
||||
|
||||
#ifndef BENCHMARK_OS_WINDOWS
|
||||
#ifndef BENCHMARK_OS_FUCHSIA
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include "check.h"
|
||||
#include "colorprint.h"
|
||||
#include "commandlineflags.h"
|
||||
#include "complexity.h"
|
||||
#include "counter.h"
|
||||
#include "internal_macros.h"
|
||||
#include "log.h"
|
||||
#include "mutex.h"
|
||||
#include "re.h"
|
||||
#include "statistics.h"
|
||||
#include "string_util.h"
|
||||
#include "thread_manager.h"
|
||||
#include "thread_timer.h"
|
||||
|
||||
DEFINE_bool(benchmark_list_tests, false,
|
||||
"Print a list of benchmarks. This option overrides all other "
|
||||
"options.");
|
||||
|
||||
DEFINE_string(benchmark_filter, ".",
|
||||
"A regular expression that specifies the set of benchmarks "
|
||||
"to execute. If this flag is empty, no benchmarks are run. "
|
||||
"If this flag is the string \"all\", all benchmarks linked "
|
||||
"into the process are run.");
|
||||
|
||||
DEFINE_double(benchmark_min_time, 0.5,
|
||||
"Minimum number of seconds we should run benchmark before "
|
||||
"results are considered significant. For cpu-time based "
|
||||
"tests, this is the lower bound on the total cpu time "
|
||||
"used by all threads that make up the test. For real-time "
|
||||
"based tests, this is the lower bound on the elapsed time "
|
||||
"of the benchmark execution, regardless of number of "
|
||||
"threads.");
|
||||
|
||||
DEFINE_int32(benchmark_repetitions, 1,
|
||||
"The number of runs of each benchmark. If greater than 1, the "
|
||||
"mean and standard deviation of the runs will be reported.");
|
||||
|
||||
DEFINE_bool(benchmark_report_aggregates_only, false,
|
||||
"Report the result of each benchmark repetitions. When 'true' is "
|
||||
"specified only the mean, standard deviation, and other statistics "
|
||||
"are reported for repeated benchmarks.");
|
||||
|
||||
DEFINE_string(benchmark_format, "console",
|
||||
"The format to use for console output. Valid values are "
|
||||
"'console', 'json', or 'csv'.");
|
||||
|
||||
DEFINE_string(benchmark_out_format, "json",
|
||||
"The format to use for file output. Valid values are "
|
||||
"'console', 'json', or 'csv'.");
|
||||
|
||||
DEFINE_string(benchmark_out, "", "The file to write additional output to");
|
||||
|
||||
DEFINE_string(benchmark_color, "auto",
|
||||
"Whether to use colors in the output. Valid values: "
|
||||
"'true'/'yes'/1, 'false'/'no'/0, and 'auto'. 'auto' means to use "
|
||||
"colors if the output is being sent to a terminal and the TERM "
|
||||
"environment variable is set to a terminal type that supports "
|
||||
"colors.");
|
||||
|
||||
DEFINE_bool(benchmark_counters_tabular, false,
|
||||
"Whether to use tabular format when printing user counters to "
|
||||
"the console. Valid values: 'true'/'yes'/1, 'false'/'no'/0."
|
||||
"Defaults to false.");
|
||||
|
||||
DEFINE_int32(v, 0, "The level of verbose logging to output");
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
namespace {
|
||||
static const size_t kMaxIterations = 1000000000;
|
||||
} // end namespace
|
||||
|
||||
namespace internal {
|
||||
|
||||
void UseCharPointer(char const volatile*) {}
|
||||
|
||||
namespace {
|
||||
|
||||
BenchmarkReporter::Run CreateRunReport(
|
||||
const benchmark::internal::Benchmark::Instance& b,
|
||||
const internal::ThreadManager::Result& results,
|
||||
double seconds) {
|
||||
// Create report about this benchmark run.
|
||||
BenchmarkReporter::Run report;
|
||||
|
||||
report.benchmark_name = b.name;
|
||||
report.error_occurred = results.has_error_;
|
||||
report.error_message = results.error_message_;
|
||||
report.report_label = results.report_label_;
|
||||
// This is the total iterations across all threads.
|
||||
report.iterations = results.iterations;
|
||||
report.time_unit = b.time_unit;
|
||||
|
||||
if (!report.error_occurred) {
|
||||
double bytes_per_second = 0;
|
||||
if (results.bytes_processed > 0 && seconds > 0.0) {
|
||||
bytes_per_second = (results.bytes_processed / seconds);
|
||||
}
|
||||
double items_per_second = 0;
|
||||
if (results.items_processed > 0 && seconds > 0.0) {
|
||||
items_per_second = (results.items_processed / seconds);
|
||||
}
|
||||
|
||||
if (b.use_manual_time) {
|
||||
report.real_accumulated_time = results.manual_time_used;
|
||||
} else {
|
||||
report.real_accumulated_time = results.real_time_used;
|
||||
}
|
||||
report.cpu_accumulated_time = results.cpu_time_used;
|
||||
report.bytes_per_second = bytes_per_second;
|
||||
report.items_per_second = items_per_second;
|
||||
report.complexity_n = results.complexity_n;
|
||||
report.complexity = b.complexity;
|
||||
report.complexity_lambda = b.complexity_lambda;
|
||||
report.statistics = b.statistics;
|
||||
report.counters = results.counters;
|
||||
internal::Finish(&report.counters, seconds, b.threads);
|
||||
}
|
||||
return report;
|
||||
}
|
||||
|
||||
// Execute one thread of benchmark b for the specified number of iterations.
|
||||
// Adds the stats collected for the thread into *total.
|
||||
void RunInThread(const benchmark::internal::Benchmark::Instance* b,
|
||||
size_t iters, int thread_id,
|
||||
internal::ThreadManager* manager) {
|
||||
internal::ThreadTimer timer;
|
||||
State st(iters, b->arg, thread_id, b->threads, &timer, manager);
|
||||
b->benchmark->Run(st);
|
||||
CHECK(st.iterations() >= st.max_iterations)
|
||||
<< "Benchmark returned before State::KeepRunning() returned false!";
|
||||
{
|
||||
MutexLock l(manager->GetBenchmarkMutex());
|
||||
internal::ThreadManager::Result& results = manager->results;
|
||||
results.iterations += st.iterations();
|
||||
results.cpu_time_used += timer.cpu_time_used();
|
||||
results.real_time_used += timer.real_time_used();
|
||||
results.manual_time_used += timer.manual_time_used();
|
||||
results.bytes_processed += st.bytes_processed();
|
||||
results.items_processed += st.items_processed();
|
||||
results.complexity_n += st.complexity_length_n();
|
||||
internal::Increment(&results.counters, st.counters);
|
||||
}
|
||||
manager->NotifyThreadComplete();
|
||||
}
|
||||
|
||||
std::vector<BenchmarkReporter::Run> RunBenchmark(
|
||||
const benchmark::internal::Benchmark::Instance& b,
|
||||
std::vector<BenchmarkReporter::Run>* complexity_reports) {
|
||||
std::vector<BenchmarkReporter::Run> reports; // return value
|
||||
|
||||
const bool has_explicit_iteration_count = b.iterations != 0;
|
||||
size_t iters = has_explicit_iteration_count ? b.iterations : 1;
|
||||
std::unique_ptr<internal::ThreadManager> manager;
|
||||
std::vector<std::thread> pool(b.threads - 1);
|
||||
const int repeats =
|
||||
b.repetitions != 0 ? b.repetitions : FLAGS_benchmark_repetitions;
|
||||
const bool report_aggregates_only =
|
||||
repeats != 1 &&
|
||||
(b.report_mode == internal::RM_Unspecified
|
||||
? FLAGS_benchmark_report_aggregates_only
|
||||
: b.report_mode == internal::RM_ReportAggregatesOnly);
|
||||
for (int repetition_num = 0; repetition_num < repeats; repetition_num++) {
|
||||
for (;;) {
|
||||
// Try benchmark
|
||||
VLOG(2) << "Running " << b.name << " for " << iters << "\n";
|
||||
|
||||
manager.reset(new internal::ThreadManager(b.threads));
|
||||
for (std::size_t ti = 0; ti < pool.size(); ++ti) {
|
||||
pool[ti] = std::thread(&RunInThread, &b, iters,
|
||||
static_cast<int>(ti + 1), manager.get());
|
||||
}
|
||||
RunInThread(&b, iters, 0, manager.get());
|
||||
manager->WaitForAllThreads();
|
||||
for (std::thread& thread : pool) thread.join();
|
||||
internal::ThreadManager::Result results;
|
||||
{
|
||||
MutexLock l(manager->GetBenchmarkMutex());
|
||||
results = manager->results;
|
||||
}
|
||||
manager.reset();
|
||||
// Adjust real/manual time stats since they were reported per thread.
|
||||
results.real_time_used /= b.threads;
|
||||
results.manual_time_used /= b.threads;
|
||||
|
||||
VLOG(2) << "Ran in " << results.cpu_time_used << "/"
|
||||
<< results.real_time_used << "\n";
|
||||
|
||||
// Base decisions off of real time if requested by this benchmark.
|
||||
double seconds = results.cpu_time_used;
|
||||
if (b.use_manual_time) {
|
||||
seconds = results.manual_time_used;
|
||||
} else if (b.use_real_time) {
|
||||
seconds = results.real_time_used;
|
||||
}
|
||||
|
||||
const double min_time =
|
||||
!IsZero(b.min_time) ? b.min_time : FLAGS_benchmark_min_time;
|
||||
|
||||
// Determine if this run should be reported; Either it has
|
||||
// run for a sufficient amount of time or because an error was reported.
|
||||
const bool should_report = repetition_num > 0
|
||||
|| has_explicit_iteration_count // An exact iteration count was requested
|
||||
|| results.has_error_
|
||||
|| iters >= kMaxIterations // No chance to try again, we hit the limit.
|
||||
|| seconds >= min_time // the elapsed time is large enough
|
||||
// CPU time is specified but the elapsed real time greatly exceeds the
|
||||
// minimum time. Note that user provided timers are except from this
|
||||
// sanity check.
|
||||
|| ((results.real_time_used >= 5 * min_time) && !b.use_manual_time);
|
||||
|
||||
if (should_report) {
|
||||
BenchmarkReporter::Run report = CreateRunReport(b, results, seconds);
|
||||
if (!report.error_occurred && b.complexity != oNone)
|
||||
complexity_reports->push_back(report);
|
||||
reports.push_back(report);
|
||||
break;
|
||||
}
|
||||
|
||||
// See how much iterations should be increased by
|
||||
// Note: Avoid division by zero with max(seconds, 1ns).
|
||||
double multiplier = min_time * 1.4 / std::max(seconds, 1e-9);
|
||||
// If our last run was at least 10% of FLAGS_benchmark_min_time then we
|
||||
// use the multiplier directly. Otherwise we use at most 10 times
|
||||
// expansion.
|
||||
// NOTE: When the last run was at least 10% of the min time the max
|
||||
// expansion should be 14x.
|
||||
bool is_significant = (seconds / min_time) > 0.1;
|
||||
multiplier = is_significant ? multiplier : std::min(10.0, multiplier);
|
||||
if (multiplier <= 1.0) multiplier = 2.0;
|
||||
double next_iters = std::max(multiplier * iters, iters + 1.0);
|
||||
if (next_iters > kMaxIterations) {
|
||||
next_iters = kMaxIterations;
|
||||
}
|
||||
VLOG(3) << "Next iters: " << next_iters << ", " << multiplier << "\n";
|
||||
iters = static_cast<int>(next_iters + 0.5);
|
||||
}
|
||||
}
|
||||
// Calculate additional statistics
|
||||
auto stat_reports = ComputeStats(reports);
|
||||
if ((b.complexity != oNone) && b.last_benchmark_instance) {
|
||||
auto additional_run_stats = ComputeBigO(*complexity_reports);
|
||||
stat_reports.insert(stat_reports.end(), additional_run_stats.begin(),
|
||||
additional_run_stats.end());
|
||||
complexity_reports->clear();
|
||||
}
|
||||
|
||||
if (report_aggregates_only) reports.clear();
|
||||
reports.insert(reports.end(), stat_reports.begin(), stat_reports.end());
|
||||
return reports;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace internal
|
||||
|
||||
State::State(size_t max_iters, const std::vector<int64_t>& ranges, int thread_i,
|
||||
int n_threads, internal::ThreadTimer* timer,
|
||||
internal::ThreadManager* manager)
|
||||
: total_iterations_(0),
|
||||
batch_leftover_(0),
|
||||
max_iterations(max_iters),
|
||||
started_(false),
|
||||
finished_(false),
|
||||
error_occurred_(false),
|
||||
range_(ranges),
|
||||
bytes_processed_(0),
|
||||
items_processed_(0),
|
||||
complexity_n_(0),
|
||||
counters(),
|
||||
thread_index(thread_i),
|
||||
threads(n_threads),
|
||||
timer_(timer),
|
||||
manager_(manager) {
|
||||
CHECK(max_iterations != 0) << "At least one iteration must be run";
|
||||
CHECK_LT(thread_index, threads) << "thread_index must be less than threads";
|
||||
|
||||
// Note: The use of offsetof below is technically undefined until C++17
|
||||
// because State is not a standard layout type. However, all compilers
|
||||
// currently provide well-defined behavior as an extension (which is
|
||||
// demonstrated since constexpr evaluation must diagnose all undefined
|
||||
// behavior). However, GCC and Clang also warn about this use of offsetof,
|
||||
// which must be suppressed.
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Winvalid-offsetof"
|
||||
#endif
|
||||
// Offset tests to ensure commonly accessed data is on the first cache line.
|
||||
const int cache_line_size = 64;
|
||||
static_assert(offsetof(State, error_occurred_) <=
|
||||
(cache_line_size - sizeof(error_occurred_)), "");
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
void State::PauseTiming() {
|
||||
// Add in time accumulated so far
|
||||
CHECK(started_ && !finished_ && !error_occurred_);
|
||||
timer_->StopTimer();
|
||||
}
|
||||
|
||||
void State::ResumeTiming() {
|
||||
CHECK(started_ && !finished_ && !error_occurred_);
|
||||
timer_->StartTimer();
|
||||
}
|
||||
|
||||
void State::SkipWithError(const char* msg) {
|
||||
CHECK(msg);
|
||||
error_occurred_ = true;
|
||||
{
|
||||
MutexLock l(manager_->GetBenchmarkMutex());
|
||||
if (manager_->results.has_error_ == false) {
|
||||
manager_->results.error_message_ = msg;
|
||||
manager_->results.has_error_ = true;
|
||||
}
|
||||
}
|
||||
total_iterations_ = 0;
|
||||
if (timer_->running()) timer_->StopTimer();
|
||||
}
|
||||
|
||||
void State::SetIterationTime(double seconds) {
|
||||
timer_->SetIterationTime(seconds);
|
||||
}
|
||||
|
||||
void State::SetLabel(const char* label) {
|
||||
MutexLock l(manager_->GetBenchmarkMutex());
|
||||
manager_->results.report_label_ = label;
|
||||
}
|
||||
|
||||
void State::StartKeepRunning() {
|
||||
CHECK(!started_ && !finished_);
|
||||
started_ = true;
|
||||
total_iterations_ = error_occurred_ ? 0 : max_iterations;
|
||||
manager_->StartStopBarrier();
|
||||
if (!error_occurred_) ResumeTiming();
|
||||
}
|
||||
|
||||
void State::FinishKeepRunning() {
|
||||
CHECK(started_ && (!finished_ || error_occurred_));
|
||||
if (!error_occurred_) {
|
||||
PauseTiming();
|
||||
}
|
||||
// Total iterations has now wrapped around past 0. Fix this.
|
||||
total_iterations_ = 0;
|
||||
finished_ = true;
|
||||
manager_->StartStopBarrier();
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
namespace {
|
||||
|
||||
void RunBenchmarks(const std::vector<Benchmark::Instance>& benchmarks,
|
||||
BenchmarkReporter* console_reporter,
|
||||
BenchmarkReporter* file_reporter) {
|
||||
// Note the file_reporter can be null.
|
||||
CHECK(console_reporter != nullptr);
|
||||
|
||||
// Determine the width of the name field using a minimum width of 10.
|
||||
bool has_repetitions = FLAGS_benchmark_repetitions > 1;
|
||||
size_t name_field_width = 10;
|
||||
size_t stat_field_width = 0;
|
||||
for (const Benchmark::Instance& benchmark : benchmarks) {
|
||||
name_field_width =
|
||||
std::max<size_t>(name_field_width, benchmark.name.size());
|
||||
has_repetitions |= benchmark.repetitions > 1;
|
||||
|
||||
for(const auto& Stat : *benchmark.statistics)
|
||||
stat_field_width = std::max<size_t>(stat_field_width, Stat.name_.size());
|
||||
}
|
||||
if (has_repetitions) name_field_width += 1 + stat_field_width;
|
||||
|
||||
// Print header here
|
||||
BenchmarkReporter::Context context;
|
||||
context.name_field_width = name_field_width;
|
||||
|
||||
// Keep track of running times of all instances of current benchmark
|
||||
std::vector<BenchmarkReporter::Run> complexity_reports;
|
||||
|
||||
// We flush streams after invoking reporter methods that write to them. This
|
||||
// ensures users get timely updates even when streams are not line-buffered.
|
||||
auto flushStreams = [](BenchmarkReporter* reporter) {
|
||||
if (!reporter) return;
|
||||
std::flush(reporter->GetOutputStream());
|
||||
std::flush(reporter->GetErrorStream());
|
||||
};
|
||||
|
||||
if (console_reporter->ReportContext(context) &&
|
||||
(!file_reporter || file_reporter->ReportContext(context))) {
|
||||
flushStreams(console_reporter);
|
||||
flushStreams(file_reporter);
|
||||
for (const auto& benchmark : benchmarks) {
|
||||
std::vector<BenchmarkReporter::Run> reports =
|
||||
RunBenchmark(benchmark, &complexity_reports);
|
||||
console_reporter->ReportRuns(reports);
|
||||
if (file_reporter) file_reporter->ReportRuns(reports);
|
||||
flushStreams(console_reporter);
|
||||
flushStreams(file_reporter);
|
||||
}
|
||||
}
|
||||
console_reporter->Finalize();
|
||||
if (file_reporter) file_reporter->Finalize();
|
||||
flushStreams(console_reporter);
|
||||
flushStreams(file_reporter);
|
||||
}
|
||||
|
||||
std::unique_ptr<BenchmarkReporter> CreateReporter(
|
||||
std::string const& name, ConsoleReporter::OutputOptions output_opts) {
|
||||
typedef std::unique_ptr<BenchmarkReporter> PtrType;
|
||||
if (name == "console") {
|
||||
return PtrType(new ConsoleReporter(output_opts));
|
||||
} else if (name == "json") {
|
||||
return PtrType(new JSONReporter);
|
||||
} else if (name == "csv") {
|
||||
return PtrType(new CSVReporter);
|
||||
} else {
|
||||
std::cerr << "Unexpected format: '" << name << "'\n";
|
||||
std::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
bool IsZero(double n) {
|
||||
return std::abs(n) < std::numeric_limits<double>::epsilon();
|
||||
}
|
||||
|
||||
ConsoleReporter::OutputOptions GetOutputOptions(bool force_no_color) {
|
||||
int output_opts = ConsoleReporter::OO_Defaults;
|
||||
if ((FLAGS_benchmark_color == "auto" && IsColorTerminal()) ||
|
||||
IsTruthyFlagValue(FLAGS_benchmark_color)) {
|
||||
output_opts |= ConsoleReporter::OO_Color;
|
||||
} else {
|
||||
output_opts &= ~ConsoleReporter::OO_Color;
|
||||
}
|
||||
if(force_no_color) {
|
||||
output_opts &= ~ConsoleReporter::OO_Color;
|
||||
}
|
||||
if(FLAGS_benchmark_counters_tabular) {
|
||||
output_opts |= ConsoleReporter::OO_Tabular;
|
||||
} else {
|
||||
output_opts &= ~ConsoleReporter::OO_Tabular;
|
||||
}
|
||||
return static_cast< ConsoleReporter::OutputOptions >(output_opts);
|
||||
}
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
size_t RunSpecifiedBenchmarks() {
|
||||
return RunSpecifiedBenchmarks(nullptr, nullptr);
|
||||
}
|
||||
|
||||
size_t RunSpecifiedBenchmarks(BenchmarkReporter* console_reporter) {
|
||||
return RunSpecifiedBenchmarks(console_reporter, nullptr);
|
||||
}
|
||||
|
||||
size_t RunSpecifiedBenchmarks(BenchmarkReporter* console_reporter,
|
||||
BenchmarkReporter* file_reporter) {
|
||||
std::string spec = FLAGS_benchmark_filter;
|
||||
if (spec.empty() || spec == "all")
|
||||
spec = "."; // Regexp that matches all benchmarks
|
||||
|
||||
// Setup the reporters
|
||||
std::ofstream output_file;
|
||||
std::unique_ptr<BenchmarkReporter> default_console_reporter;
|
||||
std::unique_ptr<BenchmarkReporter> default_file_reporter;
|
||||
if (!console_reporter) {
|
||||
default_console_reporter = internal::CreateReporter(
|
||||
FLAGS_benchmark_format, internal::GetOutputOptions());
|
||||
console_reporter = default_console_reporter.get();
|
||||
}
|
||||
auto& Out = console_reporter->GetOutputStream();
|
||||
auto& Err = console_reporter->GetErrorStream();
|
||||
|
||||
std::string const& fname = FLAGS_benchmark_out;
|
||||
if (fname.empty() && file_reporter) {
|
||||
Err << "A custom file reporter was provided but "
|
||||
"--benchmark_out=<file> was not specified."
|
||||
<< std::endl;
|
||||
std::exit(1);
|
||||
}
|
||||
if (!fname.empty()) {
|
||||
output_file.open(fname);
|
||||
if (!output_file.is_open()) {
|
||||
Err << "invalid file name: '" << fname << std::endl;
|
||||
std::exit(1);
|
||||
}
|
||||
if (!file_reporter) {
|
||||
default_file_reporter = internal::CreateReporter(
|
||||
FLAGS_benchmark_out_format, ConsoleReporter::OO_None);
|
||||
file_reporter = default_file_reporter.get();
|
||||
}
|
||||
file_reporter->SetOutputStream(&output_file);
|
||||
file_reporter->SetErrorStream(&output_file);
|
||||
}
|
||||
|
||||
std::vector<internal::Benchmark::Instance> benchmarks;
|
||||
if (!FindBenchmarksInternal(spec, &benchmarks, &Err)) return 0;
|
||||
|
||||
if (benchmarks.empty()) {
|
||||
Err << "Failed to match any benchmarks against regex: " << spec << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (FLAGS_benchmark_list_tests) {
|
||||
for (auto const& benchmark : benchmarks) Out << benchmark.name << "\n";
|
||||
} else {
|
||||
internal::RunBenchmarks(benchmarks, console_reporter, file_reporter);
|
||||
}
|
||||
|
||||
return benchmarks.size();
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
void PrintUsageAndExit() {
|
||||
fprintf(stdout,
|
||||
"benchmark"
|
||||
" [--benchmark_list_tests={true|false}]\n"
|
||||
" [--benchmark_filter=<regex>]\n"
|
||||
" [--benchmark_min_time=<min_time>]\n"
|
||||
" [--benchmark_repetitions=<num_repetitions>]\n"
|
||||
" [--benchmark_report_aggregates_only={true|false}\n"
|
||||
" [--benchmark_format=<console|json|csv>]\n"
|
||||
" [--benchmark_out=<filename>]\n"
|
||||
" [--benchmark_out_format=<json|console|csv>]\n"
|
||||
" [--benchmark_color={auto|true|false}]\n"
|
||||
" [--benchmark_counters_tabular={true|false}]\n"
|
||||
" [--v=<verbosity>]\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void ParseCommandLineFlags(int* argc, char** argv) {
|
||||
using namespace benchmark;
|
||||
BenchmarkReporter::Context::executable_name = argv[0];
|
||||
for (int i = 1; i < *argc; ++i) {
|
||||
if (ParseBoolFlag(argv[i], "benchmark_list_tests",
|
||||
&FLAGS_benchmark_list_tests) ||
|
||||
ParseStringFlag(argv[i], "benchmark_filter", &FLAGS_benchmark_filter) ||
|
||||
ParseDoubleFlag(argv[i], "benchmark_min_time",
|
||||
&FLAGS_benchmark_min_time) ||
|
||||
ParseInt32Flag(argv[i], "benchmark_repetitions",
|
||||
&FLAGS_benchmark_repetitions) ||
|
||||
ParseBoolFlag(argv[i], "benchmark_report_aggregates_only",
|
||||
&FLAGS_benchmark_report_aggregates_only) ||
|
||||
ParseStringFlag(argv[i], "benchmark_format", &FLAGS_benchmark_format) ||
|
||||
ParseStringFlag(argv[i], "benchmark_out", &FLAGS_benchmark_out) ||
|
||||
ParseStringFlag(argv[i], "benchmark_out_format",
|
||||
&FLAGS_benchmark_out_format) ||
|
||||
ParseStringFlag(argv[i], "benchmark_color", &FLAGS_benchmark_color) ||
|
||||
// "color_print" is the deprecated name for "benchmark_color".
|
||||
// TODO: Remove this.
|
||||
ParseStringFlag(argv[i], "color_print", &FLAGS_benchmark_color) ||
|
||||
ParseBoolFlag(argv[i], "benchmark_counters_tabular",
|
||||
&FLAGS_benchmark_counters_tabular) ||
|
||||
ParseInt32Flag(argv[i], "v", &FLAGS_v)) {
|
||||
for (int j = i; j != *argc - 1; ++j) argv[j] = argv[j + 1];
|
||||
|
||||
--(*argc);
|
||||
--i;
|
||||
} else if (IsFlag(argv[i], "help")) {
|
||||
PrintUsageAndExit();
|
||||
}
|
||||
}
|
||||
for (auto const* flag :
|
||||
{&FLAGS_benchmark_format, &FLAGS_benchmark_out_format})
|
||||
if (*flag != "console" && *flag != "json" && *flag != "csv") {
|
||||
PrintUsageAndExit();
|
||||
}
|
||||
if (FLAGS_benchmark_color.empty()) {
|
||||
PrintUsageAndExit();
|
||||
}
|
||||
}
|
||||
|
||||
int InitializeStreams() {
|
||||
static std::ios_base::Init init;
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
void Initialize(int* argc, char** argv) {
|
||||
internal::ParseCommandLineFlags(argc, argv);
|
||||
internal::LogLevel() = FLAGS_v;
|
||||
}
|
||||
|
||||
bool ReportUnrecognizedArguments(int argc, char** argv) {
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
fprintf(stderr, "%s: error: unrecognized command-line flag: %s\n", argv[0], argv[i]);
|
||||
}
|
||||
return argc > 1;
|
||||
}
|
||||
|
||||
} // end namespace benchmark
|
||||
@@ -1,47 +0,0 @@
|
||||
#ifndef BENCHMARK_API_INTERNAL_H
|
||||
#define BENCHMARK_API_INTERNAL_H
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <iosfwd>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace benchmark {
|
||||
namespace internal {
|
||||
|
||||
// Information kept per benchmark we may want to run
|
||||
struct Benchmark::Instance {
|
||||
std::string name;
|
||||
Benchmark* benchmark;
|
||||
ReportMode report_mode;
|
||||
std::vector<int64_t> arg;
|
||||
TimeUnit time_unit;
|
||||
int range_multiplier;
|
||||
bool use_real_time;
|
||||
bool use_manual_time;
|
||||
BigO complexity;
|
||||
BigOFunc* complexity_lambda;
|
||||
UserCounters counters;
|
||||
const std::vector<Statistics>* statistics;
|
||||
bool last_benchmark_instance;
|
||||
int repetitions;
|
||||
double min_time;
|
||||
size_t iterations;
|
||||
int threads; // Number of concurrent threads to us
|
||||
};
|
||||
|
||||
bool FindBenchmarksInternal(const std::string& re,
|
||||
std::vector<Benchmark::Instance>* benchmarks,
|
||||
std::ostream* Err);
|
||||
|
||||
bool IsZero(double n);
|
||||
|
||||
ConsoleReporter::OutputOptions GetOutputOptions(bool force_no_color = false);
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace benchmark
|
||||
|
||||
#endif // BENCHMARK_API_INTERNAL_H
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright 2018 Google Inc. All rights reserved.
|
||||
//
|
||||
// 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 "benchmark/benchmark.h"
|
||||
|
||||
BENCHMARK_MAIN();
|
||||
@@ -1,461 +0,0 @@
|
||||
// Copyright 2015 Google Inc. All rights reserved.
|
||||
//
|
||||
// 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 "benchmark_register.h"
|
||||
|
||||
#ifndef BENCHMARK_OS_WINDOWS
|
||||
#ifndef BENCHMARK_OS_FUCHSIA
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
#include "benchmark_api_internal.h"
|
||||
#include "check.h"
|
||||
#include "commandlineflags.h"
|
||||
#include "complexity.h"
|
||||
#include "internal_macros.h"
|
||||
#include "log.h"
|
||||
#include "mutex.h"
|
||||
#include "re.h"
|
||||
#include "statistics.h"
|
||||
#include "string_util.h"
|
||||
#include "timers.h"
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
namespace {
|
||||
// For non-dense Range, intermediate values are powers of kRangeMultiplier.
|
||||
static const int kRangeMultiplier = 8;
|
||||
// The size of a benchmark family determines is the number of inputs to repeat
|
||||
// the benchmark on. If this is "large" then warn the user during configuration.
|
||||
static const size_t kMaxFamilySize = 100;
|
||||
} // end namespace
|
||||
|
||||
namespace internal {
|
||||
|
||||
//=============================================================================//
|
||||
// BenchmarkFamilies
|
||||
//=============================================================================//
|
||||
|
||||
// Class for managing registered benchmarks. Note that each registered
|
||||
// benchmark identifies a family of related benchmarks to run.
|
||||
class BenchmarkFamilies {
|
||||
public:
|
||||
static BenchmarkFamilies* GetInstance();
|
||||
|
||||
// Registers a benchmark family and returns the index assigned to it.
|
||||
size_t AddBenchmark(std::unique_ptr<Benchmark> family);
|
||||
|
||||
// Clear all registered benchmark families.
|
||||
void ClearBenchmarks();
|
||||
|
||||
// Extract the list of benchmark instances that match the specified
|
||||
// regular expression.
|
||||
bool FindBenchmarks(std::string re,
|
||||
std::vector<Benchmark::Instance>* benchmarks,
|
||||
std::ostream* Err);
|
||||
|
||||
private:
|
||||
BenchmarkFamilies() {}
|
||||
|
||||
std::vector<std::unique_ptr<Benchmark>> families_;
|
||||
Mutex mutex_;
|
||||
};
|
||||
|
||||
BenchmarkFamilies* BenchmarkFamilies::GetInstance() {
|
||||
static BenchmarkFamilies instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
size_t BenchmarkFamilies::AddBenchmark(std::unique_ptr<Benchmark> family) {
|
||||
MutexLock l(mutex_);
|
||||
size_t index = families_.size();
|
||||
families_.push_back(std::move(family));
|
||||
return index;
|
||||
}
|
||||
|
||||
void BenchmarkFamilies::ClearBenchmarks() {
|
||||
MutexLock l(mutex_);
|
||||
families_.clear();
|
||||
families_.shrink_to_fit();
|
||||
}
|
||||
|
||||
bool BenchmarkFamilies::FindBenchmarks(
|
||||
std::string spec, std::vector<Benchmark::Instance>* benchmarks,
|
||||
std::ostream* ErrStream) {
|
||||
CHECK(ErrStream);
|
||||
auto& Err = *ErrStream;
|
||||
// Make regular expression out of command-line flag
|
||||
std::string error_msg;
|
||||
Regex re;
|
||||
bool isNegativeFilter = false;
|
||||
if(spec[0] == '-') {
|
||||
spec.replace(0, 1, "");
|
||||
isNegativeFilter = true;
|
||||
}
|
||||
if (!re.Init(spec, &error_msg)) {
|
||||
Err << "Could not compile benchmark re: " << error_msg << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Special list of thread counts to use when none are specified
|
||||
const std::vector<int> one_thread = {1};
|
||||
|
||||
MutexLock l(mutex_);
|
||||
for (std::unique_ptr<Benchmark>& family : families_) {
|
||||
// Family was deleted or benchmark doesn't match
|
||||
if (!family) continue;
|
||||
|
||||
if (family->ArgsCnt() == -1) {
|
||||
family->Args({});
|
||||
}
|
||||
const std::vector<int>* thread_counts =
|
||||
(family->thread_counts_.empty()
|
||||
? &one_thread
|
||||
: &static_cast<const std::vector<int>&>(family->thread_counts_));
|
||||
const size_t family_size = family->args_.size() * thread_counts->size();
|
||||
// The benchmark will be run at least 'family_size' different inputs.
|
||||
// If 'family_size' is very large warn the user.
|
||||
if (family_size > kMaxFamilySize) {
|
||||
Err << "The number of inputs is very large. " << family->name_
|
||||
<< " will be repeated at least " << family_size << " times.\n";
|
||||
}
|
||||
// reserve in the special case the regex ".", since we know the final
|
||||
// family size.
|
||||
if (spec == ".") benchmarks->reserve(family_size);
|
||||
|
||||
for (auto const& args : family->args_) {
|
||||
for (int num_threads : *thread_counts) {
|
||||
Benchmark::Instance instance;
|
||||
instance.name = family->name_;
|
||||
instance.benchmark = family.get();
|
||||
instance.report_mode = family->report_mode_;
|
||||
instance.arg = args;
|
||||
instance.time_unit = family->time_unit_;
|
||||
instance.range_multiplier = family->range_multiplier_;
|
||||
instance.min_time = family->min_time_;
|
||||
instance.iterations = family->iterations_;
|
||||
instance.repetitions = family->repetitions_;
|
||||
instance.use_real_time = family->use_real_time_;
|
||||
instance.use_manual_time = family->use_manual_time_;
|
||||
instance.complexity = family->complexity_;
|
||||
instance.complexity_lambda = family->complexity_lambda_;
|
||||
instance.statistics = &family->statistics_;
|
||||
instance.threads = num_threads;
|
||||
|
||||
// Add arguments to instance name
|
||||
size_t arg_i = 0;
|
||||
for (auto const& arg : args) {
|
||||
instance.name += "/";
|
||||
|
||||
if (arg_i < family->arg_names_.size()) {
|
||||
const auto& arg_name = family->arg_names_[arg_i];
|
||||
if (!arg_name.empty()) {
|
||||
instance.name +=
|
||||
StrFormat("%s:", family->arg_names_[arg_i].c_str());
|
||||
}
|
||||
}
|
||||
|
||||
instance.name += StrFormat("%d", arg);
|
||||
++arg_i;
|
||||
}
|
||||
|
||||
if (!IsZero(family->min_time_))
|
||||
instance.name += StrFormat("/min_time:%0.3f", family->min_time_);
|
||||
if (family->iterations_ != 0)
|
||||
instance.name += StrFormat("/iterations:%d", family->iterations_);
|
||||
if (family->repetitions_ != 0)
|
||||
instance.name += StrFormat("/repeats:%d", family->repetitions_);
|
||||
|
||||
if (family->use_manual_time_) {
|
||||
instance.name += "/manual_time";
|
||||
} else if (family->use_real_time_) {
|
||||
instance.name += "/real_time";
|
||||
}
|
||||
|
||||
// Add the number of threads used to the name
|
||||
if (!family->thread_counts_.empty()) {
|
||||
instance.name += StrFormat("/threads:%d", instance.threads);
|
||||
}
|
||||
|
||||
if ((re.Match(instance.name) && !isNegativeFilter) ||
|
||||
(!re.Match(instance.name) && isNegativeFilter)) {
|
||||
instance.last_benchmark_instance = (&args == &family->args_.back());
|
||||
benchmarks->push_back(std::move(instance));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Benchmark* RegisterBenchmarkInternal(Benchmark* bench) {
|
||||
std::unique_ptr<Benchmark> bench_ptr(bench);
|
||||
BenchmarkFamilies* families = BenchmarkFamilies::GetInstance();
|
||||
families->AddBenchmark(std::move(bench_ptr));
|
||||
return bench;
|
||||
}
|
||||
|
||||
// FIXME: This function is a hack so that benchmark.cc can access
|
||||
// `BenchmarkFamilies`
|
||||
bool FindBenchmarksInternal(const std::string& re,
|
||||
std::vector<Benchmark::Instance>* benchmarks,
|
||||
std::ostream* Err) {
|
||||
return BenchmarkFamilies::GetInstance()->FindBenchmarks(re, benchmarks, Err);
|
||||
}
|
||||
|
||||
//=============================================================================//
|
||||
// Benchmark
|
||||
//=============================================================================//
|
||||
|
||||
Benchmark::Benchmark(const char* name)
|
||||
: name_(name),
|
||||
report_mode_(RM_Unspecified),
|
||||
time_unit_(kNanosecond),
|
||||
range_multiplier_(kRangeMultiplier),
|
||||
min_time_(0),
|
||||
iterations_(0),
|
||||
repetitions_(0),
|
||||
use_real_time_(false),
|
||||
use_manual_time_(false),
|
||||
complexity_(oNone),
|
||||
complexity_lambda_(nullptr) {
|
||||
ComputeStatistics("mean", StatisticsMean);
|
||||
ComputeStatistics("median", StatisticsMedian);
|
||||
ComputeStatistics("stddev", StatisticsStdDev);
|
||||
}
|
||||
|
||||
Benchmark::~Benchmark() {}
|
||||
|
||||
Benchmark* Benchmark::Arg(int64_t x) {
|
||||
CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
|
||||
args_.push_back({x});
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Unit(TimeUnit unit) {
|
||||
time_unit_ = unit;
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Range(int64_t start, int64_t limit) {
|
||||
CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
|
||||
std::vector<int64_t> arglist;
|
||||
AddRange(&arglist, start, limit, range_multiplier_);
|
||||
|
||||
for (int64_t i : arglist) {
|
||||
args_.push_back({i});
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Ranges(
|
||||
const std::vector<std::pair<int64_t, int64_t>>& ranges) {
|
||||
CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast<int>(ranges.size()));
|
||||
std::vector<std::vector<int64_t>> arglists(ranges.size());
|
||||
std::size_t total = 1;
|
||||
for (std::size_t i = 0; i < ranges.size(); i++) {
|
||||
AddRange(&arglists[i], ranges[i].first, ranges[i].second,
|
||||
range_multiplier_);
|
||||
total *= arglists[i].size();
|
||||
}
|
||||
|
||||
std::vector<std::size_t> ctr(arglists.size(), 0);
|
||||
|
||||
for (std::size_t i = 0; i < total; i++) {
|
||||
std::vector<int64_t> tmp;
|
||||
tmp.reserve(arglists.size());
|
||||
|
||||
for (std::size_t j = 0; j < arglists.size(); j++) {
|
||||
tmp.push_back(arglists[j].at(ctr[j]));
|
||||
}
|
||||
|
||||
args_.push_back(std::move(tmp));
|
||||
|
||||
for (std::size_t j = 0; j < arglists.size(); j++) {
|
||||
if (ctr[j] + 1 < arglists[j].size()) {
|
||||
++ctr[j];
|
||||
break;
|
||||
}
|
||||
ctr[j] = 0;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::ArgName(const std::string& name) {
|
||||
CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
|
||||
arg_names_ = {name};
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::ArgNames(const std::vector<std::string>& names) {
|
||||
CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast<int>(names.size()));
|
||||
arg_names_ = names;
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::DenseRange(int64_t start, int64_t limit, int step) {
|
||||
CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
|
||||
CHECK_GE(start, 0);
|
||||
CHECK_LE(start, limit);
|
||||
for (int64_t arg = start; arg <= limit; arg += step) {
|
||||
args_.push_back({arg});
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Args(const std::vector<int64_t>& args) {
|
||||
CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast<int>(args.size()));
|
||||
args_.push_back(args);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Apply(void (*custom_arguments)(Benchmark* benchmark)) {
|
||||
custom_arguments(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::RangeMultiplier(int multiplier) {
|
||||
CHECK(multiplier > 1);
|
||||
range_multiplier_ = multiplier;
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::MinTime(double t) {
|
||||
CHECK(t > 0.0);
|
||||
CHECK(iterations_ == 0);
|
||||
min_time_ = t;
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Iterations(size_t n) {
|
||||
CHECK(n > 0);
|
||||
CHECK(IsZero(min_time_));
|
||||
iterations_ = n;
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Repetitions(int n) {
|
||||
CHECK(n > 0);
|
||||
repetitions_ = n;
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::ReportAggregatesOnly(bool value) {
|
||||
report_mode_ = value ? RM_ReportAggregatesOnly : RM_Default;
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::UseRealTime() {
|
||||
CHECK(!use_manual_time_)
|
||||
<< "Cannot set UseRealTime and UseManualTime simultaneously.";
|
||||
use_real_time_ = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::UseManualTime() {
|
||||
CHECK(!use_real_time_)
|
||||
<< "Cannot set UseRealTime and UseManualTime simultaneously.";
|
||||
use_manual_time_ = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Complexity(BigO complexity) {
|
||||
complexity_ = complexity;
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Complexity(BigOFunc* complexity) {
|
||||
complexity_lambda_ = complexity;
|
||||
complexity_ = oLambda;
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::ComputeStatistics(std::string name,
|
||||
StatisticsFunc* statistics) {
|
||||
statistics_.emplace_back(name, statistics);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Threads(int t) {
|
||||
CHECK_GT(t, 0);
|
||||
thread_counts_.push_back(t);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::ThreadRange(int min_threads, int max_threads) {
|
||||
CHECK_GT(min_threads, 0);
|
||||
CHECK_GE(max_threads, min_threads);
|
||||
|
||||
AddRange(&thread_counts_, min_threads, max_threads, 2);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::DenseThreadRange(int min_threads, int max_threads,
|
||||
int stride) {
|
||||
CHECK_GT(min_threads, 0);
|
||||
CHECK_GE(max_threads, min_threads);
|
||||
CHECK_GE(stride, 1);
|
||||
|
||||
for (auto i = min_threads; i < max_threads; i += stride) {
|
||||
thread_counts_.push_back(i);
|
||||
}
|
||||
thread_counts_.push_back(max_threads);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::ThreadPerCpu() {
|
||||
thread_counts_.push_back(CPUInfo::Get().num_cpus);
|
||||
return this;
|
||||
}
|
||||
|
||||
void Benchmark::SetName(const char* name) { name_ = name; }
|
||||
|
||||
int Benchmark::ArgsCnt() const {
|
||||
if (args_.empty()) {
|
||||
if (arg_names_.empty()) return -1;
|
||||
return static_cast<int>(arg_names_.size());
|
||||
}
|
||||
return static_cast<int>(args_.front().size());
|
||||
}
|
||||
|
||||
//=============================================================================//
|
||||
// FunctionBenchmark
|
||||
//=============================================================================//
|
||||
|
||||
void FunctionBenchmark::Run(State& st) { func_(st); }
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
void ClearRegisteredBenchmarks() {
|
||||
internal::BenchmarkFamilies::GetInstance()->ClearBenchmarks();
|
||||
}
|
||||
|
||||
} // end namespace benchmark
|
||||
@@ -1,33 +0,0 @@
|
||||
#ifndef BENCHMARK_REGISTER_H
|
||||
#define BENCHMARK_REGISTER_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "check.h"
|
||||
|
||||
template <typename T>
|
||||
void AddRange(std::vector<T>* dst, T lo, T hi, int mult) {
|
||||
CHECK_GE(lo, 0);
|
||||
CHECK_GE(hi, lo);
|
||||
CHECK_GE(mult, 2);
|
||||
|
||||
// Add "lo"
|
||||
dst->push_back(lo);
|
||||
|
||||
static const T kmax = std::numeric_limits<T>::max();
|
||||
|
||||
// Now space out the benchmarks in multiples of "mult"
|
||||
for (T i = 1; i < kmax / mult; i *= mult) {
|
||||
if (i >= hi) break;
|
||||
if (i > lo) {
|
||||
dst->push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Add "hi" (if different from "lo")
|
||||
if (hi != lo) {
|
||||
dst->push_back(hi);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BENCHMARK_REGISTER_H
|
||||
79
benchmarks/thirdparty/benchmark/src/check.h
vendored
79
benchmarks/thirdparty/benchmark/src/check.h
vendored
@@ -1,79 +0,0 @@
|
||||
#ifndef CHECK_H_
|
||||
#define CHECK_H_
|
||||
|
||||
#include <cstdlib>
|
||||
#include <ostream>
|
||||
#include <cmath>
|
||||
|
||||
#include "internal_macros.h"
|
||||
#include "log.h"
|
||||
|
||||
namespace benchmark {
|
||||
namespace internal {
|
||||
|
||||
typedef void(AbortHandlerT)();
|
||||
|
||||
inline AbortHandlerT*& GetAbortHandler() {
|
||||
static AbortHandlerT* handler = &std::abort;
|
||||
return handler;
|
||||
}
|
||||
|
||||
BENCHMARK_NORETURN inline void CallAbortHandler() {
|
||||
GetAbortHandler()();
|
||||
std::abort(); // fallback to enforce noreturn
|
||||
}
|
||||
|
||||
// CheckHandler is the class constructed by failing CHECK macros. CheckHandler
|
||||
// will log information about the failures and abort when it is destructed.
|
||||
class CheckHandler {
|
||||
public:
|
||||
CheckHandler(const char* check, const char* file, const char* func, int line)
|
||||
: log_(GetErrorLogInstance()) {
|
||||
log_ << file << ":" << line << ": " << func << ": Check `" << check
|
||||
<< "' failed. ";
|
||||
}
|
||||
|
||||
LogType& GetLog() { return log_; }
|
||||
|
||||
BENCHMARK_NORETURN ~CheckHandler() BENCHMARK_NOEXCEPT_OP(false) {
|
||||
log_ << std::endl;
|
||||
CallAbortHandler();
|
||||
}
|
||||
|
||||
CheckHandler& operator=(const CheckHandler&) = delete;
|
||||
CheckHandler(const CheckHandler&) = delete;
|
||||
CheckHandler() = delete;
|
||||
|
||||
private:
|
||||
LogType& log_;
|
||||
};
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace benchmark
|
||||
|
||||
// The CHECK macro returns a std::ostream object that can have extra information
|
||||
// written to it.
|
||||
#ifndef NDEBUG
|
||||
#define CHECK(b) \
|
||||
(b ? ::benchmark::internal::GetNullLogInstance() \
|
||||
: ::benchmark::internal::CheckHandler(#b, __FILE__, __func__, __LINE__) \
|
||||
.GetLog())
|
||||
#else
|
||||
#define CHECK(b) ::benchmark::internal::GetNullLogInstance()
|
||||
#endif
|
||||
|
||||
#define CHECK_EQ(a, b) CHECK((a) == (b))
|
||||
#define CHECK_NE(a, b) CHECK((a) != (b))
|
||||
#define CHECK_GE(a, b) CHECK((a) >= (b))
|
||||
#define CHECK_LE(a, b) CHECK((a) <= (b))
|
||||
#define CHECK_GT(a, b) CHECK((a) > (b))
|
||||
#define CHECK_LT(a, b) CHECK((a) < (b))
|
||||
|
||||
#define CHECK_FLOAT_EQ(a, b, eps) CHECK(std::fabs((a) - (b)) < (eps))
|
||||
#define CHECK_FLOAT_NE(a, b, eps) CHECK(std::fabs((a) - (b)) >= (eps))
|
||||
#define CHECK_FLOAT_GE(a, b, eps) CHECK((a) - (b) > -(eps))
|
||||
#define CHECK_FLOAT_LE(a, b, eps) CHECK((b) - (a) > -(eps))
|
||||
#define CHECK_FLOAT_GT(a, b, eps) CHECK((a) - (b) > (eps))
|
||||
#define CHECK_FLOAT_LT(a, b, eps) CHECK((b) - (a) > (eps))
|
||||
|
||||
#endif // CHECK_H_
|
||||
188
benchmarks/thirdparty/benchmark/src/colorprint.cc
vendored
188
benchmarks/thirdparty/benchmark/src/colorprint.cc
vendored
@@ -1,188 +0,0 @@
|
||||
// Copyright 2015 Google Inc. All rights reserved.
|
||||
//
|
||||
// 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 "colorprint.h"
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "check.h"
|
||||
#include "internal_macros.h"
|
||||
|
||||
#ifdef BENCHMARK_OS_WINDOWS
|
||||
#include <Windows.h>
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif // BENCHMARK_OS_WINDOWS
|
||||
|
||||
namespace benchmark {
|
||||
namespace {
|
||||
#ifdef BENCHMARK_OS_WINDOWS
|
||||
typedef WORD PlatformColorCode;
|
||||
#else
|
||||
typedef const char* PlatformColorCode;
|
||||
#endif
|
||||
|
||||
PlatformColorCode GetPlatformColorCode(LogColor color) {
|
||||
#ifdef BENCHMARK_OS_WINDOWS
|
||||
switch (color) {
|
||||
case COLOR_RED:
|
||||
return FOREGROUND_RED;
|
||||
case COLOR_GREEN:
|
||||
return FOREGROUND_GREEN;
|
||||
case COLOR_YELLOW:
|
||||
return FOREGROUND_RED | FOREGROUND_GREEN;
|
||||
case COLOR_BLUE:
|
||||
return FOREGROUND_BLUE;
|
||||
case COLOR_MAGENTA:
|
||||
return FOREGROUND_BLUE | FOREGROUND_RED;
|
||||
case COLOR_CYAN:
|
||||
return FOREGROUND_BLUE | FOREGROUND_GREEN;
|
||||
case COLOR_WHITE: // fall through to default
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
switch (color) {
|
||||
case COLOR_RED:
|
||||
return "1";
|
||||
case COLOR_GREEN:
|
||||
return "2";
|
||||
case COLOR_YELLOW:
|
||||
return "3";
|
||||
case COLOR_BLUE:
|
||||
return "4";
|
||||
case COLOR_MAGENTA:
|
||||
return "5";
|
||||
case COLOR_CYAN:
|
||||
return "6";
|
||||
case COLOR_WHITE:
|
||||
return "7";
|
||||
default:
|
||||
return nullptr;
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
std::string FormatString(const char* msg, va_list args) {
|
||||
// we might need a second shot at this, so pre-emptivly make a copy
|
||||
va_list args_cp;
|
||||
va_copy(args_cp, args);
|
||||
|
||||
std::size_t size = 256;
|
||||
char local_buff[256];
|
||||
auto ret = vsnprintf(local_buff, size, msg, args_cp);
|
||||
|
||||
va_end(args_cp);
|
||||
|
||||
// currently there is no error handling for failure, so this is hack.
|
||||
CHECK(ret >= 0);
|
||||
|
||||
if (ret == 0) // handle empty expansion
|
||||
return {};
|
||||
else if (static_cast<size_t>(ret) < size)
|
||||
return local_buff;
|
||||
else {
|
||||
// we did not provide a long enough buffer on our first attempt.
|
||||
size = (size_t)ret + 1; // + 1 for the null byte
|
||||
std::unique_ptr<char[]> buff(new char[size]);
|
||||
ret = vsnprintf(buff.get(), size, msg, args);
|
||||
CHECK(ret > 0 && ((size_t)ret) < size);
|
||||
return buff.get();
|
||||
}
|
||||
}
|
||||
|
||||
std::string FormatString(const char* msg, ...) {
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
auto tmp = FormatString(msg, args);
|
||||
va_end(args);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ColorPrintf(out, color, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void ColorPrintf(std::ostream& out, LogColor color, const char* fmt,
|
||||
va_list args) {
|
||||
#ifdef BENCHMARK_OS_WINDOWS
|
||||
((void)out); // suppress unused warning
|
||||
|
||||
const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
// Gets the current text color.
|
||||
CONSOLE_SCREEN_BUFFER_INFO buffer_info;
|
||||
GetConsoleScreenBufferInfo(stdout_handle, &buffer_info);
|
||||
const WORD old_color_attrs = buffer_info.wAttributes;
|
||||
|
||||
// We need to flush the stream buffers into the console before each
|
||||
// SetConsoleTextAttribute call lest it affect the text that is already
|
||||
// printed but has not yet reached the console.
|
||||
fflush(stdout);
|
||||
SetConsoleTextAttribute(stdout_handle,
|
||||
GetPlatformColorCode(color) | FOREGROUND_INTENSITY);
|
||||
vprintf(fmt, args);
|
||||
|
||||
fflush(stdout);
|
||||
// Restores the text color.
|
||||
SetConsoleTextAttribute(stdout_handle, old_color_attrs);
|
||||
#else
|
||||
const char* color_code = GetPlatformColorCode(color);
|
||||
if (color_code) out << FormatString("\033[0;3%sm", color_code);
|
||||
out << FormatString(fmt, args) << "\033[m";
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IsColorTerminal() {
|
||||
#if BENCHMARK_OS_WINDOWS
|
||||
// On Windows the TERM variable is usually not set, but the
|
||||
// console there does support colors.
|
||||
return 0 != _isatty(_fileno(stdout));
|
||||
#else
|
||||
// On non-Windows platforms, we rely on the TERM variable. This list of
|
||||
// supported TERM values is copied from Google Test:
|
||||
// <https://github.com/google/googletest/blob/master/googletest/src/gtest.cc#L2925>.
|
||||
const char* const SUPPORTED_TERM_VALUES[] = {
|
||||
"xterm", "xterm-color", "xterm-256color",
|
||||
"screen", "screen-256color", "tmux",
|
||||
"tmux-256color", "rxvt-unicode", "rxvt-unicode-256color",
|
||||
"linux", "cygwin",
|
||||
};
|
||||
|
||||
const char* const term = getenv("TERM");
|
||||
|
||||
bool term_supports_color = false;
|
||||
for (const char* candidate : SUPPORTED_TERM_VALUES) {
|
||||
if (term && 0 == strcmp(term, candidate)) {
|
||||
term_supports_color = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0 != isatty(fileno(stdout)) && term_supports_color;
|
||||
#endif // BENCHMARK_OS_WINDOWS
|
||||
}
|
||||
|
||||
} // end namespace benchmark
|
||||
33
benchmarks/thirdparty/benchmark/src/colorprint.h
vendored
33
benchmarks/thirdparty/benchmark/src/colorprint.h
vendored
@@ -1,33 +0,0 @@
|
||||
#ifndef BENCHMARK_COLORPRINT_H_
|
||||
#define BENCHMARK_COLORPRINT_H_
|
||||
|
||||
#include <cstdarg>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
namespace benchmark {
|
||||
enum LogColor {
|
||||
COLOR_DEFAULT,
|
||||
COLOR_RED,
|
||||
COLOR_GREEN,
|
||||
COLOR_YELLOW,
|
||||
COLOR_BLUE,
|
||||
COLOR_MAGENTA,
|
||||
COLOR_CYAN,
|
||||
COLOR_WHITE
|
||||
};
|
||||
|
||||
std::string FormatString(const char* msg, va_list args);
|
||||
std::string FormatString(const char* msg, ...);
|
||||
|
||||
void ColorPrintf(std::ostream& out, LogColor color, const char* fmt,
|
||||
va_list args);
|
||||
void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, ...);
|
||||
|
||||
// Returns true if stdout appears to be a terminal that supports colored
|
||||
// output, false otherwise.
|
||||
bool IsColorTerminal();
|
||||
|
||||
} // end namespace benchmark
|
||||
|
||||
#endif // BENCHMARK_COLORPRINT_H_
|
||||
@@ -1,218 +0,0 @@
|
||||
// Copyright 2015 Google Inc. All rights reserved.
|
||||
//
|
||||
// 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 "commandlineflags.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
|
||||
namespace benchmark {
|
||||
// Parses 'str' for a 32-bit signed integer. If successful, writes
|
||||
// the result to *value and returns true; otherwise leaves *value
|
||||
// unchanged and returns false.
|
||||
bool ParseInt32(const std::string& src_text, const char* str, int32_t* value) {
|
||||
// Parses the environment variable as a decimal integer.
|
||||
char* end = nullptr;
|
||||
const long long_value = strtol(str, &end, 10); // NOLINT
|
||||
|
||||
// Has strtol() consumed all characters in the string?
|
||||
if (*end != '\0') {
|
||||
// No - an invalid character was encountered.
|
||||
std::cerr << src_text << " is expected to be a 32-bit integer, "
|
||||
<< "but actually has value \"" << str << "\".\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is the parsed value in the range of an Int32?
|
||||
const int32_t result = static_cast<int32_t>(long_value);
|
||||
if (long_value == std::numeric_limits<long>::max() ||
|
||||
long_value == std::numeric_limits<long>::min() ||
|
||||
// The parsed value overflows as a long. (strtol() returns
|
||||
// LONG_MAX or LONG_MIN when the input overflows.)
|
||||
result != long_value
|
||||
// The parsed value overflows as an Int32.
|
||||
) {
|
||||
std::cerr << src_text << " is expected to be a 32-bit integer, "
|
||||
<< "but actually has value \"" << str << "\", "
|
||||
<< "which overflows.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
*value = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Parses 'str' for a double. If successful, writes the result to *value and
|
||||
// returns true; otherwise leaves *value unchanged and returns false.
|
||||
bool ParseDouble(const std::string& src_text, const char* str, double* value) {
|
||||
// Parses the environment variable as a decimal integer.
|
||||
char* end = nullptr;
|
||||
const double double_value = strtod(str, &end); // NOLINT
|
||||
|
||||
// Has strtol() consumed all characters in the string?
|
||||
if (*end != '\0') {
|
||||
// No - an invalid character was encountered.
|
||||
std::cerr << src_text << " is expected to be a double, "
|
||||
<< "but actually has value \"" << str << "\".\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
*value = double_value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns the name of the environment variable corresponding to the
|
||||
// given flag. For example, FlagToEnvVar("foo") will return
|
||||
// "BENCHMARK_FOO" in the open-source version.
|
||||
static std::string FlagToEnvVar(const char* flag) {
|
||||
const std::string flag_str(flag);
|
||||
|
||||
std::string env_var;
|
||||
for (size_t i = 0; i != flag_str.length(); ++i)
|
||||
env_var += static_cast<char>(::toupper(flag_str.c_str()[i]));
|
||||
|
||||
return "BENCHMARK_" + env_var;
|
||||
}
|
||||
|
||||
// Reads and returns the Boolean environment variable corresponding to
|
||||
// the given flag; if it's not set, returns default_value.
|
||||
//
|
||||
// The value is considered true iff it's not "0".
|
||||
bool BoolFromEnv(const char* flag, bool default_value) {
|
||||
const std::string env_var = FlagToEnvVar(flag);
|
||||
const char* const string_value = getenv(env_var.c_str());
|
||||
return string_value == nullptr ? default_value
|
||||
: strcmp(string_value, "0") != 0;
|
||||
}
|
||||
|
||||
// Reads and returns a 32-bit integer stored in the environment
|
||||
// variable corresponding to the given flag; if it isn't set or
|
||||
// doesn't represent a valid 32-bit integer, returns default_value.
|
||||
int32_t Int32FromEnv(const char* flag, int32_t default_value) {
|
||||
const std::string env_var = FlagToEnvVar(flag);
|
||||
const char* const string_value = getenv(env_var.c_str());
|
||||
if (string_value == nullptr) {
|
||||
// The environment variable is not set.
|
||||
return default_value;
|
||||
}
|
||||
|
||||
int32_t result = default_value;
|
||||
if (!ParseInt32(std::string("Environment variable ") + env_var, string_value,
|
||||
&result)) {
|
||||
std::cout << "The default value " << default_value << " is used.\n";
|
||||
return default_value;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Reads and returns the string environment variable corresponding to
|
||||
// the given flag; if it's not set, returns default_value.
|
||||
const char* StringFromEnv(const char* flag, const char* default_value) {
|
||||
const std::string env_var = FlagToEnvVar(flag);
|
||||
const char* const value = getenv(env_var.c_str());
|
||||
return value == nullptr ? default_value : value;
|
||||
}
|
||||
|
||||
// Parses a string as a command line flag. The string should have
|
||||
// the format "--flag=value". When def_optional is true, the "=value"
|
||||
// part can be omitted.
|
||||
//
|
||||
// Returns the value of the flag, or nullptr if the parsing failed.
|
||||
const char* ParseFlagValue(const char* str, const char* flag,
|
||||
bool def_optional) {
|
||||
// str and flag must not be nullptr.
|
||||
if (str == nullptr || flag == nullptr) return nullptr;
|
||||
|
||||
// The flag must start with "--".
|
||||
const std::string flag_str = std::string("--") + std::string(flag);
|
||||
const size_t flag_len = flag_str.length();
|
||||
if (strncmp(str, flag_str.c_str(), flag_len) != 0) return nullptr;
|
||||
|
||||
// Skips the flag name.
|
||||
const char* flag_end = str + flag_len;
|
||||
|
||||
// When def_optional is true, it's OK to not have a "=value" part.
|
||||
if (def_optional && (flag_end[0] == '\0')) return flag_end;
|
||||
|
||||
// If def_optional is true and there are more characters after the
|
||||
// flag name, or if def_optional is false, there must be a '=' after
|
||||
// the flag name.
|
||||
if (flag_end[0] != '=') return nullptr;
|
||||
|
||||
// Returns the string after "=".
|
||||
return flag_end + 1;
|
||||
}
|
||||
|
||||
bool ParseBoolFlag(const char* str, const char* flag, bool* value) {
|
||||
// Gets the value of the flag as a string.
|
||||
const char* const value_str = ParseFlagValue(str, flag, true);
|
||||
|
||||
// Aborts if the parsing failed.
|
||||
if (value_str == nullptr) return false;
|
||||
|
||||
// Converts the string value to a bool.
|
||||
*value = IsTruthyFlagValue(value_str);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParseInt32Flag(const char* str, const char* flag, int32_t* value) {
|
||||
// Gets the value of the flag as a string.
|
||||
const char* const value_str = ParseFlagValue(str, flag, false);
|
||||
|
||||
// Aborts if the parsing failed.
|
||||
if (value_str == nullptr) return false;
|
||||
|
||||
// Sets *value to the value of the flag.
|
||||
return ParseInt32(std::string("The value of flag --") + flag, value_str,
|
||||
value);
|
||||
}
|
||||
|
||||
bool ParseDoubleFlag(const char* str, const char* flag, double* value) {
|
||||
// Gets the value of the flag as a string.
|
||||
const char* const value_str = ParseFlagValue(str, flag, false);
|
||||
|
||||
// Aborts if the parsing failed.
|
||||
if (value_str == nullptr) return false;
|
||||
|
||||
// Sets *value to the value of the flag.
|
||||
return ParseDouble(std::string("The value of flag --") + flag, value_str,
|
||||
value);
|
||||
}
|
||||
|
||||
bool ParseStringFlag(const char* str, const char* flag, std::string* value) {
|
||||
// Gets the value of the flag as a string.
|
||||
const char* const value_str = ParseFlagValue(str, flag, false);
|
||||
|
||||
// Aborts if the parsing failed.
|
||||
if (value_str == nullptr) return false;
|
||||
|
||||
*value = value_str;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsFlag(const char* str, const char* flag) {
|
||||
return (ParseFlagValue(str, flag, true) != nullptr);
|
||||
}
|
||||
|
||||
bool IsTruthyFlagValue(const std::string& value) {
|
||||
if (value.empty()) return true;
|
||||
char ch = value[0];
|
||||
return isalnum(ch) &&
|
||||
!(ch == '0' || ch == 'f' || ch == 'F' || ch == 'n' || ch == 'N');
|
||||
}
|
||||
} // end namespace benchmark
|
||||
@@ -1,79 +0,0 @@
|
||||
#ifndef BENCHMARK_COMMANDLINEFLAGS_H_
|
||||
#define BENCHMARK_COMMANDLINEFLAGS_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
// Macro for referencing flags.
|
||||
#define FLAG(name) FLAGS_##name
|
||||
|
||||
// Macros for declaring flags.
|
||||
#define DECLARE_bool(name) extern bool FLAG(name)
|
||||
#define DECLARE_int32(name) extern int32_t FLAG(name)
|
||||
#define DECLARE_int64(name) extern int64_t FLAG(name)
|
||||
#define DECLARE_double(name) extern double FLAG(name)
|
||||
#define DECLARE_string(name) extern std::string FLAG(name)
|
||||
|
||||
// Macros for defining flags.
|
||||
#define DEFINE_bool(name, default_val, doc) bool FLAG(name) = (default_val)
|
||||
#define DEFINE_int32(name, default_val, doc) int32_t FLAG(name) = (default_val)
|
||||
#define DEFINE_int64(name, default_val, doc) int64_t FLAG(name) = (default_val)
|
||||
#define DEFINE_double(name, default_val, doc) double FLAG(name) = (default_val)
|
||||
#define DEFINE_string(name, default_val, doc) \
|
||||
std::string FLAG(name) = (default_val)
|
||||
|
||||
namespace benchmark {
|
||||
// Parses 'str' for a 32-bit signed integer. If successful, writes the result
|
||||
// to *value and returns true; otherwise leaves *value unchanged and returns
|
||||
// false.
|
||||
bool ParseInt32(const std::string& src_text, const char* str, int32_t* value);
|
||||
|
||||
// Parses a bool/Int32/string from the environment variable
|
||||
// corresponding to the given Google Test flag.
|
||||
bool BoolFromEnv(const char* flag, bool default_val);
|
||||
int32_t Int32FromEnv(const char* flag, int32_t default_val);
|
||||
double DoubleFromEnv(const char* flag, double default_val);
|
||||
const char* StringFromEnv(const char* flag, const char* default_val);
|
||||
|
||||
// Parses a string for a bool flag, in the form of either
|
||||
// "--flag=value" or "--flag".
|
||||
//
|
||||
// In the former case, the value is taken as true if it passes IsTruthyValue().
|
||||
//
|
||||
// In the latter case, the value is taken as true.
|
||||
//
|
||||
// On success, stores the value of the flag in *value, and returns
|
||||
// true. On failure, returns false without changing *value.
|
||||
bool ParseBoolFlag(const char* str, const char* flag, bool* value);
|
||||
|
||||
// Parses a string for an Int32 flag, in the form of
|
||||
// "--flag=value".
|
||||
//
|
||||
// On success, stores the value of the flag in *value, and returns
|
||||
// true. On failure, returns false without changing *value.
|
||||
bool ParseInt32Flag(const char* str, const char* flag, int32_t* value);
|
||||
|
||||
// Parses a string for a Double flag, in the form of
|
||||
// "--flag=value".
|
||||
//
|
||||
// On success, stores the value of the flag in *value, and returns
|
||||
// true. On failure, returns false without changing *value.
|
||||
bool ParseDoubleFlag(const char* str, const char* flag, double* value);
|
||||
|
||||
// Parses a string for a string flag, in the form of
|
||||
// "--flag=value".
|
||||
//
|
||||
// On success, stores the value of the flag in *value, and returns
|
||||
// true. On failure, returns false without changing *value.
|
||||
bool ParseStringFlag(const char* str, const char* flag, std::string* value);
|
||||
|
||||
// Returns true if the string matches the flag.
|
||||
bool IsFlag(const char* str, const char* flag);
|
||||
|
||||
// Returns true unless value starts with one of: '0', 'f', 'F', 'n' or 'N', or
|
||||
// some non-alphanumeric character. As a special case, also returns true if
|
||||
// value is the empty string.
|
||||
bool IsTruthyFlagValue(const std::string& value);
|
||||
} // end namespace benchmark
|
||||
|
||||
#endif // BENCHMARK_COMMANDLINEFLAGS_H_
|
||||
220
benchmarks/thirdparty/benchmark/src/complexity.cc
vendored
220
benchmarks/thirdparty/benchmark/src/complexity.cc
vendored
@@ -1,220 +0,0 @@
|
||||
// Copyright 2016 Ismael Jimenez Martinez. All rights reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// Source project : https://github.com/ismaelJimenez/cpp.leastsq
|
||||
// Adapted to be used with google benchmark
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include "check.h"
|
||||
#include "complexity.h"
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
// Internal function to calculate the different scalability forms
|
||||
BigOFunc* FittingCurve(BigO complexity) {
|
||||
switch (complexity) {
|
||||
case oN:
|
||||
return [](int64_t n) -> double { return static_cast<double>(n); };
|
||||
case oNSquared:
|
||||
return [](int64_t n) -> double { return std::pow(n, 2); };
|
||||
case oNCubed:
|
||||
return [](int64_t n) -> double { return std::pow(n, 3); };
|
||||
case oLogN:
|
||||
return [](int64_t n) { return log2(n); };
|
||||
case oNLogN:
|
||||
return [](int64_t n) { return n * log2(n); };
|
||||
case o1:
|
||||
default:
|
||||
return [](int64_t) { return 1.0; };
|
||||
}
|
||||
}
|
||||
|
||||
// Function to return an string for the calculated complexity
|
||||
std::string GetBigOString(BigO complexity) {
|
||||
switch (complexity) {
|
||||
case oN:
|
||||
return "N";
|
||||
case oNSquared:
|
||||
return "N^2";
|
||||
case oNCubed:
|
||||
return "N^3";
|
||||
case oLogN:
|
||||
return "lgN";
|
||||
case oNLogN:
|
||||
return "NlgN";
|
||||
case o1:
|
||||
return "(1)";
|
||||
default:
|
||||
return "f(N)";
|
||||
}
|
||||
}
|
||||
|
||||
// Find the coefficient for the high-order term in the running time, by
|
||||
// minimizing the sum of squares of relative error, for the fitting curve
|
||||
// given by the lambda expression.
|
||||
// - n : Vector containing the size of the benchmark tests.
|
||||
// - time : Vector containing the times for the benchmark tests.
|
||||
// - fitting_curve : lambda expression (e.g. [](int64_t n) {return n; };).
|
||||
|
||||
// For a deeper explanation on the algorithm logic, look the README file at
|
||||
// http://github.com/ismaelJimenez/Minimal-Cpp-Least-Squared-Fit
|
||||
|
||||
LeastSq MinimalLeastSq(const std::vector<int64_t>& n,
|
||||
const std::vector<double>& time,
|
||||
BigOFunc* fitting_curve) {
|
||||
double sigma_gn = 0.0;
|
||||
double sigma_gn_squared = 0.0;
|
||||
double sigma_time = 0.0;
|
||||
double sigma_time_gn = 0.0;
|
||||
|
||||
// Calculate least square fitting parameter
|
||||
for (size_t i = 0; i < n.size(); ++i) {
|
||||
double gn_i = fitting_curve(n[i]);
|
||||
sigma_gn += gn_i;
|
||||
sigma_gn_squared += gn_i * gn_i;
|
||||
sigma_time += time[i];
|
||||
sigma_time_gn += time[i] * gn_i;
|
||||
}
|
||||
|
||||
LeastSq result;
|
||||
result.complexity = oLambda;
|
||||
|
||||
// Calculate complexity.
|
||||
result.coef = sigma_time_gn / sigma_gn_squared;
|
||||
|
||||
// Calculate RMS
|
||||
double rms = 0.0;
|
||||
for (size_t i = 0; i < n.size(); ++i) {
|
||||
double fit = result.coef * fitting_curve(n[i]);
|
||||
rms += pow((time[i] - fit), 2);
|
||||
}
|
||||
|
||||
// Normalized RMS by the mean of the observed values
|
||||
double mean = sigma_time / n.size();
|
||||
result.rms = sqrt(rms / n.size()) / mean;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Find the coefficient for the high-order term in the running time, by
|
||||
// minimizing the sum of squares of relative error.
|
||||
// - n : Vector containing the size of the benchmark tests.
|
||||
// - time : Vector containing the times for the benchmark tests.
|
||||
// - complexity : If different than oAuto, the fitting curve will stick to
|
||||
// this one. If it is oAuto, it will be calculated the best
|
||||
// fitting curve.
|
||||
LeastSq MinimalLeastSq(const std::vector<int64_t>& n,
|
||||
const std::vector<double>& time, const BigO complexity) {
|
||||
CHECK_EQ(n.size(), time.size());
|
||||
CHECK_GE(n.size(), 2); // Do not compute fitting curve is less than two
|
||||
// benchmark runs are given
|
||||
CHECK_NE(complexity, oNone);
|
||||
|
||||
LeastSq best_fit;
|
||||
|
||||
if (complexity == oAuto) {
|
||||
std::vector<BigO> fit_curves = {oLogN, oN, oNLogN, oNSquared, oNCubed};
|
||||
|
||||
// Take o1 as default best fitting curve
|
||||
best_fit = MinimalLeastSq(n, time, FittingCurve(o1));
|
||||
best_fit.complexity = o1;
|
||||
|
||||
// Compute all possible fitting curves and stick to the best one
|
||||
for (const auto& fit : fit_curves) {
|
||||
LeastSq current_fit = MinimalLeastSq(n, time, FittingCurve(fit));
|
||||
if (current_fit.rms < best_fit.rms) {
|
||||
best_fit = current_fit;
|
||||
best_fit.complexity = fit;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
best_fit = MinimalLeastSq(n, time, FittingCurve(complexity));
|
||||
best_fit.complexity = complexity;
|
||||
}
|
||||
|
||||
return best_fit;
|
||||
}
|
||||
|
||||
std::vector<BenchmarkReporter::Run> ComputeBigO(
|
||||
const std::vector<BenchmarkReporter::Run>& reports) {
|
||||
typedef BenchmarkReporter::Run Run;
|
||||
std::vector<Run> results;
|
||||
|
||||
if (reports.size() < 2) return results;
|
||||
|
||||
// Accumulators.
|
||||
std::vector<int64_t> n;
|
||||
std::vector<double> real_time;
|
||||
std::vector<double> cpu_time;
|
||||
|
||||
// Populate the accumulators.
|
||||
for (const Run& run : reports) {
|
||||
CHECK_GT(run.complexity_n, 0) << "Did you forget to call SetComplexityN?";
|
||||
n.push_back(run.complexity_n);
|
||||
real_time.push_back(run.real_accumulated_time / run.iterations);
|
||||
cpu_time.push_back(run.cpu_accumulated_time / run.iterations);
|
||||
}
|
||||
|
||||
LeastSq result_cpu;
|
||||
LeastSq result_real;
|
||||
|
||||
if (reports[0].complexity == oLambda) {
|
||||
result_cpu = MinimalLeastSq(n, cpu_time, reports[0].complexity_lambda);
|
||||
result_real = MinimalLeastSq(n, real_time, reports[0].complexity_lambda);
|
||||
} else {
|
||||
result_cpu = MinimalLeastSq(n, cpu_time, reports[0].complexity);
|
||||
result_real = MinimalLeastSq(n, real_time, result_cpu.complexity);
|
||||
}
|
||||
std::string benchmark_name =
|
||||
reports[0].benchmark_name.substr(0, reports[0].benchmark_name.find('/'));
|
||||
|
||||
// Get the data from the accumulator to BenchmarkReporter::Run's.
|
||||
Run big_o;
|
||||
big_o.benchmark_name = benchmark_name + "_BigO";
|
||||
big_o.iterations = 0;
|
||||
big_o.real_accumulated_time = result_real.coef;
|
||||
big_o.cpu_accumulated_time = result_cpu.coef;
|
||||
big_o.report_big_o = true;
|
||||
big_o.complexity = result_cpu.complexity;
|
||||
|
||||
// All the time results are reported after being multiplied by the
|
||||
// time unit multiplier. But since RMS is a relative quantity it
|
||||
// should not be multiplied at all. So, here, we _divide_ it by the
|
||||
// multiplier so that when it is multiplied later the result is the
|
||||
// correct one.
|
||||
double multiplier = GetTimeUnitMultiplier(reports[0].time_unit);
|
||||
|
||||
// Only add label to mean/stddev if it is same for all runs
|
||||
Run rms;
|
||||
big_o.report_label = reports[0].report_label;
|
||||
rms.benchmark_name = benchmark_name + "_RMS";
|
||||
rms.report_label = big_o.report_label;
|
||||
rms.iterations = 0;
|
||||
rms.real_accumulated_time = result_real.rms / multiplier;
|
||||
rms.cpu_accumulated_time = result_cpu.rms / multiplier;
|
||||
rms.report_rms = true;
|
||||
rms.complexity = result_cpu.complexity;
|
||||
// don't forget to keep the time unit, or we won't be able to
|
||||
// recover the correct value.
|
||||
rms.time_unit = reports[0].time_unit;
|
||||
|
||||
results.push_back(big_o);
|
||||
results.push_back(rms);
|
||||
return results;
|
||||
}
|
||||
|
||||
} // end namespace benchmark
|
||||
55
benchmarks/thirdparty/benchmark/src/complexity.h
vendored
55
benchmarks/thirdparty/benchmark/src/complexity.h
vendored
@@ -1,55 +0,0 @@
|
||||
// Copyright 2016 Ismael Jimenez Martinez. All rights reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// Source project : https://github.com/ismaelJimenez/cpp.leastsq
|
||||
// Adapted to be used with google benchmark
|
||||
|
||||
#ifndef COMPLEXITY_H_
|
||||
#define COMPLEXITY_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
// Return a vector containing the bigO and RMS information for the specified
|
||||
// list of reports. If 'reports.size() < 2' an empty vector is returned.
|
||||
std::vector<BenchmarkReporter::Run> ComputeBigO(
|
||||
const std::vector<BenchmarkReporter::Run>& reports);
|
||||
|
||||
// This data structure will contain the result returned by MinimalLeastSq
|
||||
// - coef : Estimated coeficient for the high-order term as
|
||||
// interpolated from data.
|
||||
// - rms : Normalized Root Mean Squared Error.
|
||||
// - complexity : Scalability form (e.g. oN, oNLogN). In case a scalability
|
||||
// form has been provided to MinimalLeastSq this will return
|
||||
// the same value. In case BigO::oAuto has been selected, this
|
||||
// parameter will return the best fitting curve detected.
|
||||
|
||||
struct LeastSq {
|
||||
LeastSq() : coef(0.0), rms(0.0), complexity(oNone) {}
|
||||
|
||||
double coef;
|
||||
double rms;
|
||||
BigO complexity;
|
||||
};
|
||||
|
||||
// Function to return an string for the calculated complexity
|
||||
std::string GetBigOString(BigO complexity);
|
||||
|
||||
} // end namespace benchmark
|
||||
|
||||
#endif // COMPLEXITY_H_
|
||||
@@ -1,182 +0,0 @@
|
||||
// Copyright 2015 Google Inc. All rights reserved.
|
||||
//
|
||||
// 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 "benchmark/benchmark.h"
|
||||
#include "complexity.h"
|
||||
#include "counter.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include "check.h"
|
||||
#include "colorprint.h"
|
||||
#include "commandlineflags.h"
|
||||
#include "internal_macros.h"
|
||||
#include "string_util.h"
|
||||
#include "timers.h"
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
bool ConsoleReporter::ReportContext(const Context& context) {
|
||||
name_field_width_ = context.name_field_width;
|
||||
printed_header_ = false;
|
||||
prev_counters_.clear();
|
||||
|
||||
PrintBasicContext(&GetErrorStream(), context);
|
||||
|
||||
#ifdef BENCHMARK_OS_WINDOWS
|
||||
if ((output_options_ & OO_Color) && &std::cout != &GetOutputStream()) {
|
||||
GetErrorStream()
|
||||
<< "Color printing is only supported for stdout on windows."
|
||||
" Disabling color printing\n";
|
||||
output_options_ = static_cast< OutputOptions >(output_options_ & ~OO_Color);
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ConsoleReporter::PrintHeader(const Run& run) {
|
||||
std::string str = FormatString("%-*s %13s %13s %10s", static_cast<int>(name_field_width_),
|
||||
"Benchmark", "Time", "CPU", "Iterations");
|
||||
if(!run.counters.empty()) {
|
||||
if(output_options_ & OO_Tabular) {
|
||||
for(auto const& c : run.counters) {
|
||||
str += FormatString(" %10s", c.first.c_str());
|
||||
}
|
||||
} else {
|
||||
str += " UserCounters...";
|
||||
}
|
||||
}
|
||||
str += "\n";
|
||||
std::string line = std::string(str.length(), '-');
|
||||
GetOutputStream() << line << "\n" << str << line << "\n";
|
||||
}
|
||||
|
||||
void ConsoleReporter::ReportRuns(const std::vector<Run>& reports) {
|
||||
for (const auto& run : reports) {
|
||||
// print the header:
|
||||
// --- if none was printed yet
|
||||
bool print_header = !printed_header_;
|
||||
// --- or if the format is tabular and this run
|
||||
// has different fields from the prev header
|
||||
print_header |= (output_options_ & OO_Tabular) &&
|
||||
(!internal::SameNames(run.counters, prev_counters_));
|
||||
if (print_header) {
|
||||
printed_header_ = true;
|
||||
prev_counters_ = run.counters;
|
||||
PrintHeader(run);
|
||||
}
|
||||
// As an alternative to printing the headers like this, we could sort
|
||||
// the benchmarks by header and then print. But this would require
|
||||
// waiting for the full results before printing, or printing twice.
|
||||
PrintRunData(run);
|
||||
}
|
||||
}
|
||||
|
||||
static void IgnoreColorPrint(std::ostream& out, LogColor, const char* fmt,
|
||||
...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
out << FormatString(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void ConsoleReporter::PrintRunData(const Run& result) {
|
||||
typedef void(PrinterFn)(std::ostream&, LogColor, const char*, ...);
|
||||
auto& Out = GetOutputStream();
|
||||
PrinterFn* printer = (output_options_ & OO_Color) ?
|
||||
(PrinterFn*)ColorPrintf : IgnoreColorPrint;
|
||||
auto name_color =
|
||||
(result.report_big_o || result.report_rms) ? COLOR_BLUE : COLOR_GREEN;
|
||||
printer(Out, name_color, "%-*s ", name_field_width_,
|
||||
result.benchmark_name.c_str());
|
||||
|
||||
if (result.error_occurred) {
|
||||
printer(Out, COLOR_RED, "ERROR OCCURRED: \'%s\'",
|
||||
result.error_message.c_str());
|
||||
printer(Out, COLOR_DEFAULT, "\n");
|
||||
return;
|
||||
}
|
||||
// Format bytes per second
|
||||
std::string rate;
|
||||
if (result.bytes_per_second > 0) {
|
||||
rate = StrCat(" ", HumanReadableNumber(result.bytes_per_second), "B/s");
|
||||
}
|
||||
|
||||
// Format items per second
|
||||
std::string items;
|
||||
if (result.items_per_second > 0) {
|
||||
items =
|
||||
StrCat(" ", HumanReadableNumber(result.items_per_second), " items/s");
|
||||
}
|
||||
|
||||
const double real_time = result.GetAdjustedRealTime();
|
||||
const double cpu_time = result.GetAdjustedCPUTime();
|
||||
|
||||
if (result.report_big_o) {
|
||||
std::string big_o = GetBigOString(result.complexity);
|
||||
printer(Out, COLOR_YELLOW, "%10.2f %s %10.2f %s ", real_time, big_o.c_str(),
|
||||
cpu_time, big_o.c_str());
|
||||
} else if (result.report_rms) {
|
||||
printer(Out, COLOR_YELLOW, "%10.0f %% %10.0f %% ", real_time * 100,
|
||||
cpu_time * 100);
|
||||
} else {
|
||||
const char* timeLabel = GetTimeUnitString(result.time_unit);
|
||||
printer(Out, COLOR_YELLOW, "%10.0f %s %10.0f %s ", real_time, timeLabel,
|
||||
cpu_time, timeLabel);
|
||||
}
|
||||
|
||||
if (!result.report_big_o && !result.report_rms) {
|
||||
printer(Out, COLOR_CYAN, "%10lld", result.iterations);
|
||||
}
|
||||
|
||||
for (auto& c : result.counters) {
|
||||
const std::size_t cNameLen = std::max(std::string::size_type(10),
|
||||
c.first.length());
|
||||
auto const& s = HumanReadableNumber(c.second.value, 1000);
|
||||
if (output_options_ & OO_Tabular) {
|
||||
if (c.second.flags & Counter::kIsRate) {
|
||||
printer(Out, COLOR_DEFAULT, " %*s/s", cNameLen - 2, s.c_str());
|
||||
} else {
|
||||
printer(Out, COLOR_DEFAULT, " %*s", cNameLen, s.c_str());
|
||||
}
|
||||
} else {
|
||||
const char* unit = (c.second.flags & Counter::kIsRate) ? "/s" : "";
|
||||
printer(Out, COLOR_DEFAULT, " %s=%s%s", c.first.c_str(), s.c_str(),
|
||||
unit);
|
||||
}
|
||||
}
|
||||
|
||||
if (!rate.empty()) {
|
||||
printer(Out, COLOR_DEFAULT, " %*s", 13, rate.c_str());
|
||||
}
|
||||
|
||||
if (!items.empty()) {
|
||||
printer(Out, COLOR_DEFAULT, " %*s", 18, items.c_str());
|
||||
}
|
||||
|
||||
if (!result.report_label.empty()) {
|
||||
printer(Out, COLOR_DEFAULT, " %s", result.report_label.c_str());
|
||||
}
|
||||
|
||||
printer(Out, COLOR_DEFAULT, "\n");
|
||||
}
|
||||
|
||||
} // end namespace benchmark
|
||||
68
benchmarks/thirdparty/benchmark/src/counter.cc
vendored
68
benchmarks/thirdparty/benchmark/src/counter.cc
vendored
@@ -1,68 +0,0 @@
|
||||
// Copyright 2015 Google Inc. All rights reserved.
|
||||
//
|
||||
// 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 "counter.h"
|
||||
|
||||
namespace benchmark {
|
||||
namespace internal {
|
||||
|
||||
double Finish(Counter const& c, double cpu_time, double num_threads) {
|
||||
double v = c.value;
|
||||
if (c.flags & Counter::kIsRate) {
|
||||
v /= cpu_time;
|
||||
}
|
||||
if (c.flags & Counter::kAvgThreads) {
|
||||
v /= num_threads;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
void Finish(UserCounters *l, double cpu_time, double num_threads) {
|
||||
for (auto &c : *l) {
|
||||
c.second.value = Finish(c.second, cpu_time, num_threads);
|
||||
}
|
||||
}
|
||||
|
||||
void Increment(UserCounters *l, UserCounters const& r) {
|
||||
// add counters present in both or just in *l
|
||||
for (auto &c : *l) {
|
||||
auto it = r.find(c.first);
|
||||
if (it != r.end()) {
|
||||
c.second.value = c.second + it->second;
|
||||
}
|
||||
}
|
||||
// add counters present in r, but not in *l
|
||||
for (auto const &tc : r) {
|
||||
auto it = l->find(tc.first);
|
||||
if (it == l->end()) {
|
||||
(*l)[tc.first] = tc.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SameNames(UserCounters const& l, UserCounters const& r) {
|
||||
if (&l == &r) return true;
|
||||
if (l.size() != r.size()) {
|
||||
return false;
|
||||
}
|
||||
for (auto const& c : l) {
|
||||
if (r.find(c.first) == r.end()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace benchmark
|
||||
26
benchmarks/thirdparty/benchmark/src/counter.h
vendored
26
benchmarks/thirdparty/benchmark/src/counter.h
vendored
@@ -1,26 +0,0 @@
|
||||
// Copyright 2015 Google Inc. All rights reserved.
|
||||
//
|
||||
// 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 "benchmark/benchmark.h"
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
// these counter-related functions are hidden to reduce API surface.
|
||||
namespace internal {
|
||||
void Finish(UserCounters *l, double time, double num_threads);
|
||||
void Increment(UserCounters *l, UserCounters const& r);
|
||||
bool SameNames(UserCounters const& l, UserCounters const& r);
|
||||
} // end namespace internal
|
||||
|
||||
} //end namespace benchmark
|
||||
149
benchmarks/thirdparty/benchmark/src/csv_reporter.cc
vendored
149
benchmarks/thirdparty/benchmark/src/csv_reporter.cc
vendored
@@ -1,149 +0,0 @@
|
||||
// Copyright 2015 Google Inc. All rights reserved.
|
||||
//
|
||||
// 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 "benchmark/benchmark.h"
|
||||
#include "complexity.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include "string_util.h"
|
||||
#include "timers.h"
|
||||
#include "check.h"
|
||||
|
||||
// File format reference: http://edoceo.com/utilitas/csv-file-format.
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
namespace {
|
||||
std::vector<std::string> elements = {
|
||||
"name", "iterations", "real_time", "cpu_time",
|
||||
"time_unit", "bytes_per_second", "items_per_second", "label",
|
||||
"error_occurred", "error_message"};
|
||||
} // namespace
|
||||
|
||||
bool CSVReporter::ReportContext(const Context& context) {
|
||||
PrintBasicContext(&GetErrorStream(), context);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CSVReporter::ReportRuns(const std::vector<Run> & reports) {
|
||||
std::ostream& Out = GetOutputStream();
|
||||
|
||||
if (!printed_header_) {
|
||||
// save the names of all the user counters
|
||||
for (const auto& run : reports) {
|
||||
for (const auto& cnt : run.counters) {
|
||||
user_counter_names_.insert(cnt.first);
|
||||
}
|
||||
}
|
||||
|
||||
// print the header
|
||||
for (auto B = elements.begin(); B != elements.end();) {
|
||||
Out << *B++;
|
||||
if (B != elements.end()) Out << ",";
|
||||
}
|
||||
for (auto B = user_counter_names_.begin(); B != user_counter_names_.end();) {
|
||||
Out << ",\"" << *B++ << "\"";
|
||||
}
|
||||
Out << "\n";
|
||||
|
||||
printed_header_ = true;
|
||||
} else {
|
||||
// check that all the current counters are saved in the name set
|
||||
for (const auto& run : reports) {
|
||||
for (const auto& cnt : run.counters) {
|
||||
CHECK(user_counter_names_.find(cnt.first) != user_counter_names_.end())
|
||||
<< "All counters must be present in each run. "
|
||||
<< "Counter named \"" << cnt.first
|
||||
<< "\" was not in a run after being added to the header";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// print results for each run
|
||||
for (const auto& run : reports) {
|
||||
PrintRunData(run);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CSVReporter::PrintRunData(const Run & run) {
|
||||
std::ostream& Out = GetOutputStream();
|
||||
|
||||
// Field with embedded double-quote characters must be doubled and the field
|
||||
// delimited with double-quotes.
|
||||
std::string name = run.benchmark_name;
|
||||
ReplaceAll(&name, "\"", "\"\"");
|
||||
Out << '"' << name << "\",";
|
||||
if (run.error_occurred) {
|
||||
Out << std::string(elements.size() - 3, ',');
|
||||
Out << "true,";
|
||||
std::string msg = run.error_message;
|
||||
ReplaceAll(&msg, "\"", "\"\"");
|
||||
Out << '"' << msg << "\"\n";
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not print iteration on bigO and RMS report
|
||||
if (!run.report_big_o && !run.report_rms) {
|
||||
Out << run.iterations;
|
||||
}
|
||||
Out << ",";
|
||||
|
||||
Out << run.GetAdjustedRealTime() << ",";
|
||||
Out << run.GetAdjustedCPUTime() << ",";
|
||||
|
||||
// Do not print timeLabel on bigO and RMS report
|
||||
if (run.report_big_o) {
|
||||
Out << GetBigOString(run.complexity);
|
||||
} else if (!run.report_rms) {
|
||||
Out << GetTimeUnitString(run.time_unit);
|
||||
}
|
||||
Out << ",";
|
||||
|
||||
if (run.bytes_per_second > 0.0) {
|
||||
Out << run.bytes_per_second;
|
||||
}
|
||||
Out << ",";
|
||||
if (run.items_per_second > 0.0) {
|
||||
Out << run.items_per_second;
|
||||
}
|
||||
Out << ",";
|
||||
if (!run.report_label.empty()) {
|
||||
// Field with embedded double-quote characters must be doubled and the field
|
||||
// delimited with double-quotes.
|
||||
std::string label = run.report_label;
|
||||
ReplaceAll(&label, "\"", "\"\"");
|
||||
Out << "\"" << label << "\"";
|
||||
}
|
||||
Out << ",,"; // for error_occurred and error_message
|
||||
|
||||
// Print user counters
|
||||
for (const auto &ucn : user_counter_names_) {
|
||||
auto it = run.counters.find(ucn);
|
||||
if(it == run.counters.end()) {
|
||||
Out << ",";
|
||||
} else {
|
||||
Out << "," << it->second;
|
||||
}
|
||||
}
|
||||
Out << '\n';
|
||||
}
|
||||
|
||||
} // end namespace benchmark
|
||||
177
benchmarks/thirdparty/benchmark/src/cycleclock.h
vendored
177
benchmarks/thirdparty/benchmark/src/cycleclock.h
vendored
@@ -1,177 +0,0 @@
|
||||
// ----------------------------------------------------------------------
|
||||
// CycleClock
|
||||
// A CycleClock tells you the current time in Cycles. The "time"
|
||||
// is actually time since power-on. This is like time() but doesn't
|
||||
// involve a system call and is much more precise.
|
||||
//
|
||||
// NOTE: Not all cpu/platform/kernel combinations guarantee that this
|
||||
// clock increments at a constant rate or is synchronized across all logical
|
||||
// cpus in a system.
|
||||
//
|
||||
// If you need the above guarantees, please consider using a different
|
||||
// API. There are efforts to provide an interface which provides a millisecond
|
||||
// granularity and implemented as a memory read. A memory read is generally
|
||||
// cheaper than the CycleClock for many architectures.
|
||||
//
|
||||
// Also, in some out of order CPU implementations, the CycleClock is not
|
||||
// serializing. So if you're trying to count at cycles granularity, your
|
||||
// data might be inaccurate due to out of order instruction execution.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
#ifndef BENCHMARK_CYCLECLOCK_H_
|
||||
#define BENCHMARK_CYCLECLOCK_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
#include "internal_macros.h"
|
||||
|
||||
#if defined(BENCHMARK_OS_MACOSX)
|
||||
#include <mach/mach_time.h>
|
||||
#endif
|
||||
// For MSVC, we want to use '_asm rdtsc' when possible (since it works
|
||||
// with even ancient MSVC compilers), and when not possible the
|
||||
// __rdtsc intrinsic, declared in <intrin.h>. Unfortunately, in some
|
||||
// environments, <windows.h> and <intrin.h> have conflicting
|
||||
// declarations of some other intrinsics, breaking compilation.
|
||||
// Therefore, we simply declare __rdtsc ourselves. See also
|
||||
// http://connect.microsoft.com/VisualStudio/feedback/details/262047
|
||||
#if defined(COMPILER_MSVC) && !defined(_M_IX86)
|
||||
extern "C" uint64_t __rdtsc();
|
||||
#pragma intrinsic(__rdtsc)
|
||||
#endif
|
||||
|
||||
#ifndef BENCHMARK_OS_WINDOWS
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#ifdef BENCHMARK_OS_EMSCRIPTEN
|
||||
#include <emscripten.h>
|
||||
#endif
|
||||
|
||||
namespace benchmark {
|
||||
// NOTE: only i386 and x86_64 have been well tested.
|
||||
// PPC, sparc, alpha, and ia64 are based on
|
||||
// http://peter.kuscsik.com/wordpress/?p=14
|
||||
// with modifications by m3b. See also
|
||||
// https://setisvn.ssl.berkeley.edu/svn/lib/fftw-3.0.1/kernel/cycle.h
|
||||
namespace cycleclock {
|
||||
// This should return the number of cycles since power-on. Thread-safe.
|
||||
inline BENCHMARK_ALWAYS_INLINE int64_t Now() {
|
||||
#if defined(BENCHMARK_OS_MACOSX)
|
||||
// this goes at the top because we need ALL Macs, regardless of
|
||||
// architecture, to return the number of "mach time units" that
|
||||
// have passed since startup. See sysinfo.cc where
|
||||
// InitializeSystemInfo() sets the supposed cpu clock frequency of
|
||||
// macs to the number of mach time units per second, not actual
|
||||
// CPU clock frequency (which can change in the face of CPU
|
||||
// frequency scaling). Also note that when the Mac sleeps, this
|
||||
// counter pauses; it does not continue counting, nor does it
|
||||
// reset to zero.
|
||||
return mach_absolute_time();
|
||||
#elif defined(BENCHMARK_OS_EMSCRIPTEN)
|
||||
// this goes above x86-specific code because old versions of Emscripten
|
||||
// define __x86_64__, although they have nothing to do with it.
|
||||
return static_cast<int64_t>(emscripten_get_now() * 1e+6);
|
||||
#elif defined(__i386__)
|
||||
int64_t ret;
|
||||
__asm__ volatile("rdtsc" : "=A"(ret));
|
||||
return ret;
|
||||
#elif defined(__x86_64__) || defined(__amd64__)
|
||||
uint64_t low, high;
|
||||
__asm__ volatile("rdtsc" : "=a"(low), "=d"(high));
|
||||
return (high << 32) | low;
|
||||
#elif defined(__powerpc__) || defined(__ppc__)
|
||||
// This returns a time-base, which is not always precisely a cycle-count.
|
||||
int64_t tbl, tbu0, tbu1;
|
||||
asm("mftbu %0" : "=r"(tbu0));
|
||||
asm("mftb %0" : "=r"(tbl));
|
||||
asm("mftbu %0" : "=r"(tbu1));
|
||||
tbl &= -static_cast<int64_t>(tbu0 == tbu1);
|
||||
// high 32 bits in tbu1; low 32 bits in tbl (tbu0 is garbage)
|
||||
return (tbu1 << 32) | tbl;
|
||||
#elif defined(__sparc__)
|
||||
int64_t tick;
|
||||
asm(".byte 0x83, 0x41, 0x00, 0x00");
|
||||
asm("mov %%g1, %0" : "=r"(tick));
|
||||
return tick;
|
||||
#elif defined(__ia64__)
|
||||
int64_t itc;
|
||||
asm("mov %0 = ar.itc" : "=r"(itc));
|
||||
return itc;
|
||||
#elif defined(COMPILER_MSVC) && defined(_M_IX86)
|
||||
// Older MSVC compilers (like 7.x) don't seem to support the
|
||||
// __rdtsc intrinsic properly, so I prefer to use _asm instead
|
||||
// when I know it will work. Otherwise, I'll use __rdtsc and hope
|
||||
// the code is being compiled with a non-ancient compiler.
|
||||
_asm rdtsc
|
||||
#elif defined(COMPILER_MSVC)
|
||||
return __rdtsc();
|
||||
#elif defined(BENCHMARK_OS_NACL)
|
||||
// Native Client validator on x86/x86-64 allows RDTSC instructions,
|
||||
// and this case is handled above. Native Client validator on ARM
|
||||
// rejects MRC instructions (used in the ARM-specific sequence below),
|
||||
// so we handle it here. Portable Native Client compiles to
|
||||
// architecture-agnostic bytecode, which doesn't provide any
|
||||
// cycle counter access mnemonics.
|
||||
|
||||
// Native Client does not provide any API to access cycle counter.
|
||||
// Use clock_gettime(CLOCK_MONOTONIC, ...) instead of gettimeofday
|
||||
// because is provides nanosecond resolution (which is noticable at
|
||||
// least for PNaCl modules running on x86 Mac & Linux).
|
||||
// Initialize to always return 0 if clock_gettime fails.
|
||||
struct timespec ts = { 0, 0 };
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return static_cast<int64_t>(ts.tv_sec) * 1000000000 + ts.tv_nsec;
|
||||
#elif defined(__aarch64__)
|
||||
// System timer of ARMv8 runs at a different frequency than the CPU's.
|
||||
// The frequency is fixed, typically in the range 1-50MHz. It can be
|
||||
// read at CNTFRQ special register. We assume the OS has set up
|
||||
// the virtual timer properly.
|
||||
int64_t virtual_timer_value;
|
||||
asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value));
|
||||
return virtual_timer_value;
|
||||
#elif defined(__ARM_ARCH)
|
||||
// V6 is the earliest arch that has a standard cyclecount
|
||||
// Native Client validator doesn't allow MRC instructions.
|
||||
#if (__ARM_ARCH >= 6)
|
||||
uint32_t pmccntr;
|
||||
uint32_t pmuseren;
|
||||
uint32_t pmcntenset;
|
||||
// Read the user mode perf monitor counter access permissions.
|
||||
asm volatile("mrc p15, 0, %0, c9, c14, 0" : "=r"(pmuseren));
|
||||
if (pmuseren & 1) { // Allows reading perfmon counters for user mode code.
|
||||
asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r"(pmcntenset));
|
||||
if (pmcntenset & 0x80000000ul) { // Is it counting?
|
||||
asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(pmccntr));
|
||||
// The counter is set up to count every 64th cycle
|
||||
return static_cast<int64_t>(pmccntr) * 64; // Should optimize to << 6
|
||||
}
|
||||
}
|
||||
#endif
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
return static_cast<int64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
|
||||
#elif defined(__mips__)
|
||||
// mips apparently only allows rdtsc for superusers, so we fall
|
||||
// back to gettimeofday. It's possible clock_gettime would be better.
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
return static_cast<int64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
|
||||
#elif defined(__s390__) // Covers both s390 and s390x.
|
||||
// Return the CPU clock.
|
||||
uint64_t tsc;
|
||||
asm("stck %0" : "=Q" (tsc) : : "cc");
|
||||
return tsc;
|
||||
#else
|
||||
// The soft failover to a generic implementation is automatic only for ARM.
|
||||
// For other platforms the developer is expected to make an attempt to create
|
||||
// a fast implementation and use generic version if nothing better is available.
|
||||
#error You need to define CycleTimer for your OS and CPU
|
||||
#endif
|
||||
}
|
||||
} // end namespace cycleclock
|
||||
} // end namespace benchmark
|
||||
|
||||
#endif // BENCHMARK_CYCLECLOCK_H_
|
||||
@@ -1,89 +0,0 @@
|
||||
#ifndef BENCHMARK_INTERNAL_MACROS_H_
|
||||
#define BENCHMARK_INTERNAL_MACROS_H_
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
|
||||
#ifndef __has_feature
|
||||
#define __has_feature(x) 0
|
||||
#endif
|
||||
#ifndef __has_builtin
|
||||
#define __has_builtin(x) 0
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
#if !defined(COMPILER_CLANG)
|
||||
#define COMPILER_CLANG
|
||||
#endif
|
||||
#elif defined(_MSC_VER)
|
||||
#if !defined(COMPILER_MSVC)
|
||||
#define COMPILER_MSVC
|
||||
#endif
|
||||
#elif defined(__GNUC__)
|
||||
#if !defined(COMPILER_GCC)
|
||||
#define COMPILER_GCC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if __has_feature(cxx_attributes)
|
||||
#define BENCHMARK_NORETURN [[noreturn]]
|
||||
#elif defined(__GNUC__)
|
||||
#define BENCHMARK_NORETURN __attribute__((noreturn))
|
||||
#elif defined(COMPILER_MSVC)
|
||||
#define BENCHMARK_NORETURN __declspec(noreturn)
|
||||
#else
|
||||
#define BENCHMARK_NORETURN
|
||||
#endif
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
#define BENCHMARK_OS_CYGWIN 1
|
||||
#elif defined(_WIN32)
|
||||
#define BENCHMARK_OS_WINDOWS 1
|
||||
#elif defined(__APPLE__)
|
||||
#define BENCHMARK_OS_APPLE 1
|
||||
#include "TargetConditionals.h"
|
||||
#if defined(TARGET_OS_MAC)
|
||||
#define BENCHMARK_OS_MACOSX 1
|
||||
#if defined(TARGET_OS_IPHONE)
|
||||
#define BENCHMARK_OS_IOS 1
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(__FreeBSD__)
|
||||
#define BENCHMARK_OS_FREEBSD 1
|
||||
#elif defined(__NetBSD__)
|
||||
#define BENCHMARK_OS_NETBSD 1
|
||||
#elif defined(__OpenBSD__)
|
||||
#define BENCHMARK_OS_OPENBSD 1
|
||||
#elif defined(__linux__)
|
||||
#define BENCHMARK_OS_LINUX 1
|
||||
#elif defined(__native_client__)
|
||||
#define BENCHMARK_OS_NACL 1
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
#define BENCHMARK_OS_EMSCRIPTEN 1
|
||||
#elif defined(__rtems__)
|
||||
#define BENCHMARK_OS_RTEMS 1
|
||||
#elif defined(__Fuchsia__)
|
||||
#define BENCHMARK_OS_FUCHSIA 1
|
||||
#elif defined (__SVR4) && defined (__sun)
|
||||
#define BENCHMARK_OS_SOLARIS 1
|
||||
#endif
|
||||
|
||||
#if !__has_feature(cxx_exceptions) && !defined(__cpp_exceptions) \
|
||||
&& !defined(__EXCEPTIONS)
|
||||
#define BENCHMARK_HAS_NO_EXCEPTIONS
|
||||
#endif
|
||||
|
||||
#if defined(COMPILER_CLANG) || defined(COMPILER_GCC)
|
||||
#define BENCHMARK_MAYBE_UNUSED __attribute__((unused))
|
||||
#else
|
||||
#define BENCHMARK_MAYBE_UNUSED
|
||||
#endif
|
||||
|
||||
#if defined(COMPILER_GCC) || __has_builtin(__builtin_unreachable)
|
||||
#define BENCHMARK_UNREACHABLE() __builtin_unreachable()
|
||||
#elif defined(COMPILER_MSVC)
|
||||
#define BENCHMARK_UNREACHABLE() __assume(false)
|
||||
#else
|
||||
#define BENCHMARK_UNREACHABLE() ((void)0)
|
||||
#endif
|
||||
|
||||
#endif // BENCHMARK_INTERNAL_MACROS_H_
|
||||
205
benchmarks/thirdparty/benchmark/src/json_reporter.cc
vendored
205
benchmarks/thirdparty/benchmark/src/json_reporter.cc
vendored
@@ -1,205 +0,0 @@
|
||||
// Copyright 2015 Google Inc. All rights reserved.
|
||||
//
|
||||
// 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 "benchmark/benchmark.h"
|
||||
#include "complexity.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
#include <iomanip> // for setprecision
|
||||
#include <limits>
|
||||
|
||||
#include "string_util.h"
|
||||
#include "timers.h"
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string FormatKV(std::string const& key, std::string const& value) {
|
||||
return StrFormat("\"%s\": \"%s\"", key.c_str(), value.c_str());
|
||||
}
|
||||
|
||||
std::string FormatKV(std::string const& key, const char* value) {
|
||||
return StrFormat("\"%s\": \"%s\"", key.c_str(), value);
|
||||
}
|
||||
|
||||
std::string FormatKV(std::string const& key, bool value) {
|
||||
return StrFormat("\"%s\": %s", key.c_str(), value ? "true" : "false");
|
||||
}
|
||||
|
||||
std::string FormatKV(std::string const& key, int64_t value) {
|
||||
std::stringstream ss;
|
||||
ss << '"' << key << "\": " << value;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string FormatKV(std::string const& key, double value) {
|
||||
std::stringstream ss;
|
||||
ss << '"' << key << "\": ";
|
||||
|
||||
const auto max_digits10 = std::numeric_limits<decltype (value)>::max_digits10;
|
||||
const auto max_fractional_digits10 = max_digits10 - 1;
|
||||
|
||||
ss << std::scientific << std::setprecision(max_fractional_digits10) << value;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
int64_t RoundDouble(double v) { return static_cast<int64_t>(v + 0.5); }
|
||||
|
||||
} // end namespace
|
||||
|
||||
bool JSONReporter::ReportContext(const Context& context) {
|
||||
std::ostream& out = GetOutputStream();
|
||||
|
||||
out << "{\n";
|
||||
std::string inner_indent(2, ' ');
|
||||
|
||||
// Open context block and print context information.
|
||||
out << inner_indent << "\"context\": {\n";
|
||||
std::string indent(4, ' ');
|
||||
|
||||
std::string walltime_value = LocalDateTimeString();
|
||||
out << indent << FormatKV("date", walltime_value) << ",\n";
|
||||
|
||||
if (Context::executable_name) {
|
||||
out << indent << FormatKV("executable", Context::executable_name) << ",\n";
|
||||
}
|
||||
|
||||
CPUInfo const& info = context.cpu_info;
|
||||
out << indent << FormatKV("num_cpus", static_cast<int64_t>(info.num_cpus))
|
||||
<< ",\n";
|
||||
out << indent
|
||||
<< FormatKV("mhz_per_cpu",
|
||||
RoundDouble(info.cycles_per_second / 1000000.0))
|
||||
<< ",\n";
|
||||
out << indent << FormatKV("cpu_scaling_enabled", info.scaling_enabled)
|
||||
<< ",\n";
|
||||
|
||||
out << indent << "\"caches\": [\n";
|
||||
indent = std::string(6, ' ');
|
||||
std::string cache_indent(8, ' ');
|
||||
for (size_t i = 0; i < info.caches.size(); ++i) {
|
||||
auto& CI = info.caches[i];
|
||||
out << indent << "{\n";
|
||||
out << cache_indent << FormatKV("type", CI.type) << ",\n";
|
||||
out << cache_indent << FormatKV("level", static_cast<int64_t>(CI.level))
|
||||
<< ",\n";
|
||||
out << cache_indent
|
||||
<< FormatKV("size", static_cast<int64_t>(CI.size) * 1000u) << ",\n";
|
||||
out << cache_indent
|
||||
<< FormatKV("num_sharing", static_cast<int64_t>(CI.num_sharing))
|
||||
<< "\n";
|
||||
out << indent << "}";
|
||||
if (i != info.caches.size() - 1) out << ",";
|
||||
out << "\n";
|
||||
}
|
||||
indent = std::string(4, ' ');
|
||||
out << indent << "],\n";
|
||||
|
||||
#if defined(NDEBUG)
|
||||
const char build_type[] = "release";
|
||||
#else
|
||||
const char build_type[] = "debug";
|
||||
#endif
|
||||
out << indent << FormatKV("library_build_type", build_type) << "\n";
|
||||
// Close context block and open the list of benchmarks.
|
||||
out << inner_indent << "},\n";
|
||||
out << inner_indent << "\"benchmarks\": [\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
void JSONReporter::ReportRuns(std::vector<Run> const& reports) {
|
||||
if (reports.empty()) {
|
||||
return;
|
||||
}
|
||||
std::string indent(4, ' ');
|
||||
std::ostream& out = GetOutputStream();
|
||||
if (!first_report_) {
|
||||
out << ",\n";
|
||||
}
|
||||
first_report_ = false;
|
||||
|
||||
for (auto it = reports.begin(); it != reports.end(); ++it) {
|
||||
out << indent << "{\n";
|
||||
PrintRunData(*it);
|
||||
out << indent << '}';
|
||||
auto it_cp = it;
|
||||
if (++it_cp != reports.end()) {
|
||||
out << ",\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JSONReporter::Finalize() {
|
||||
// Close the list of benchmarks and the top level object.
|
||||
GetOutputStream() << "\n ]\n}\n";
|
||||
}
|
||||
|
||||
void JSONReporter::PrintRunData(Run const& run) {
|
||||
std::string indent(6, ' ');
|
||||
std::ostream& out = GetOutputStream();
|
||||
out << indent << FormatKV("name", run.benchmark_name) << ",\n";
|
||||
if (run.error_occurred) {
|
||||
out << indent << FormatKV("error_occurred", run.error_occurred) << ",\n";
|
||||
out << indent << FormatKV("error_message", run.error_message) << ",\n";
|
||||
}
|
||||
if (!run.report_big_o && !run.report_rms) {
|
||||
out << indent << FormatKV("iterations", run.iterations) << ",\n";
|
||||
out << indent
|
||||
<< FormatKV("real_time", run.GetAdjustedRealTime())
|
||||
<< ",\n";
|
||||
out << indent
|
||||
<< FormatKV("cpu_time", run.GetAdjustedCPUTime());
|
||||
out << ",\n"
|
||||
<< indent << FormatKV("time_unit", GetTimeUnitString(run.time_unit));
|
||||
} else if (run.report_big_o) {
|
||||
out << indent
|
||||
<< FormatKV("cpu_coefficient", run.GetAdjustedCPUTime())
|
||||
<< ",\n";
|
||||
out << indent
|
||||
<< FormatKV("real_coefficient", run.GetAdjustedRealTime())
|
||||
<< ",\n";
|
||||
out << indent << FormatKV("big_o", GetBigOString(run.complexity)) << ",\n";
|
||||
out << indent << FormatKV("time_unit", GetTimeUnitString(run.time_unit));
|
||||
} else if (run.report_rms) {
|
||||
out << indent
|
||||
<< FormatKV("rms", run.GetAdjustedCPUTime());
|
||||
}
|
||||
if (run.bytes_per_second > 0.0) {
|
||||
out << ",\n"
|
||||
<< indent
|
||||
<< FormatKV("bytes_per_second", run.bytes_per_second);
|
||||
}
|
||||
if (run.items_per_second > 0.0) {
|
||||
out << ",\n"
|
||||
<< indent
|
||||
<< FormatKV("items_per_second", run.items_per_second);
|
||||
}
|
||||
for(auto &c : run.counters) {
|
||||
out << ",\n"
|
||||
<< indent
|
||||
<< FormatKV(c.first, c.second);
|
||||
}
|
||||
if (!run.report_label.empty()) {
|
||||
out << ",\n" << indent << FormatKV("label", run.report_label);
|
||||
}
|
||||
out << '\n';
|
||||
}
|
||||
|
||||
} // end namespace benchmark
|
||||
73
benchmarks/thirdparty/benchmark/src/log.h
vendored
73
benchmarks/thirdparty/benchmark/src/log.h
vendored
@@ -1,73 +0,0 @@
|
||||
#ifndef BENCHMARK_LOG_H_
|
||||
#define BENCHMARK_LOG_H_
|
||||
|
||||
#include <iostream>
|
||||
#include <ostream>
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
|
||||
namespace benchmark {
|
||||
namespace internal {
|
||||
|
||||
typedef std::basic_ostream<char>&(EndLType)(std::basic_ostream<char>&);
|
||||
|
||||
class LogType {
|
||||
friend LogType& GetNullLogInstance();
|
||||
friend LogType& GetErrorLogInstance();
|
||||
|
||||
// FIXME: Add locking to output.
|
||||
template <class Tp>
|
||||
friend LogType& operator<<(LogType&, Tp const&);
|
||||
friend LogType& operator<<(LogType&, EndLType*);
|
||||
|
||||
private:
|
||||
LogType(std::ostream* out) : out_(out) {}
|
||||
std::ostream* out_;
|
||||
BENCHMARK_DISALLOW_COPY_AND_ASSIGN(LogType);
|
||||
};
|
||||
|
||||
template <class Tp>
|
||||
LogType& operator<<(LogType& log, Tp const& value) {
|
||||
if (log.out_) {
|
||||
*log.out_ << value;
|
||||
}
|
||||
return log;
|
||||
}
|
||||
|
||||
inline LogType& operator<<(LogType& log, EndLType* m) {
|
||||
if (log.out_) {
|
||||
*log.out_ << m;
|
||||
}
|
||||
return log;
|
||||
}
|
||||
|
||||
inline int& LogLevel() {
|
||||
static int log_level = 0;
|
||||
return log_level;
|
||||
}
|
||||
|
||||
inline LogType& GetNullLogInstance() {
|
||||
static LogType log(nullptr);
|
||||
return log;
|
||||
}
|
||||
|
||||
inline LogType& GetErrorLogInstance() {
|
||||
static LogType log(&std::clog);
|
||||
return log;
|
||||
}
|
||||
|
||||
inline LogType& GetLogInstanceForLevel(int level) {
|
||||
if (level <= LogLevel()) {
|
||||
return GetErrorLogInstance();
|
||||
}
|
||||
return GetNullLogInstance();
|
||||
}
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace benchmark
|
||||
|
||||
#define VLOG(x) \
|
||||
(::benchmark::internal::GetLogInstanceForLevel(x) << "-- LOG(" << x << "):" \
|
||||
" ")
|
||||
|
||||
#endif
|
||||
155
benchmarks/thirdparty/benchmark/src/mutex.h
vendored
155
benchmarks/thirdparty/benchmark/src/mutex.h
vendored
@@ -1,155 +0,0 @@
|
||||
#ifndef BENCHMARK_MUTEX_H_
|
||||
#define BENCHMARK_MUTEX_H_
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
|
||||
#include "check.h"
|
||||
|
||||
// Enable thread safety attributes only with clang.
|
||||
// The attributes can be safely erased when compiling with other compilers.
|
||||
#if defined(HAVE_THREAD_SAFETY_ATTRIBUTES)
|
||||
#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
|
||||
#else
|
||||
#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
|
||||
#endif
|
||||
|
||||
#define CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
|
||||
|
||||
#define SCOPED_CAPABILITY THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
|
||||
|
||||
#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
|
||||
|
||||
#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
|
||||
|
||||
#define ACQUIRED_BEFORE(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
|
||||
|
||||
#define ACQUIRED_AFTER(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
|
||||
|
||||
#define REQUIRES(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
|
||||
|
||||
#define REQUIRES_SHARED(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
|
||||
|
||||
#define ACQUIRE(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
|
||||
|
||||
#define ACQUIRE_SHARED(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
|
||||
|
||||
#define RELEASE(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
|
||||
|
||||
#define RELEASE_SHARED(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
|
||||
|
||||
#define TRY_ACQUIRE(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
|
||||
|
||||
#define TRY_ACQUIRE_SHARED(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
|
||||
|
||||
#define EXCLUDES(...) THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
|
||||
|
||||
#define ASSERT_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
|
||||
|
||||
#define ASSERT_SHARED_CAPABILITY(x) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
|
||||
|
||||
#define RETURN_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
|
||||
|
||||
#define NO_THREAD_SAFETY_ANALYSIS \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
typedef std::condition_variable Condition;
|
||||
|
||||
// NOTE: Wrappers for std::mutex and std::unique_lock are provided so that
|
||||
// we can annotate them with thread safety attributes and use the
|
||||
// -Wthread-safety warning with clang. The standard library types cannot be
|
||||
// used directly because they do not provided the required annotations.
|
||||
class CAPABILITY("mutex") Mutex {
|
||||
public:
|
||||
Mutex() {}
|
||||
|
||||
void lock() ACQUIRE() { mut_.lock(); }
|
||||
void unlock() RELEASE() { mut_.unlock(); }
|
||||
std::mutex& native_handle() { return mut_; }
|
||||
|
||||
private:
|
||||
std::mutex mut_;
|
||||
};
|
||||
|
||||
class SCOPED_CAPABILITY MutexLock {
|
||||
typedef std::unique_lock<std::mutex> MutexLockImp;
|
||||
|
||||
public:
|
||||
MutexLock(Mutex& m) ACQUIRE(m) : ml_(m.native_handle()) {}
|
||||
~MutexLock() RELEASE() {}
|
||||
MutexLockImp& native_handle() { return ml_; }
|
||||
|
||||
private:
|
||||
MutexLockImp ml_;
|
||||
};
|
||||
|
||||
class Barrier {
|
||||
public:
|
||||
Barrier(int num_threads) : running_threads_(num_threads) {}
|
||||
|
||||
// Called by each thread
|
||||
bool wait() EXCLUDES(lock_) {
|
||||
bool last_thread = false;
|
||||
{
|
||||
MutexLock ml(lock_);
|
||||
last_thread = createBarrier(ml);
|
||||
}
|
||||
if (last_thread) phase_condition_.notify_all();
|
||||
return last_thread;
|
||||
}
|
||||
|
||||
void removeThread() EXCLUDES(lock_) {
|
||||
MutexLock ml(lock_);
|
||||
--running_threads_;
|
||||
if (entered_ != 0) phase_condition_.notify_all();
|
||||
}
|
||||
|
||||
private:
|
||||
Mutex lock_;
|
||||
Condition phase_condition_;
|
||||
int running_threads_;
|
||||
|
||||
// State for barrier management
|
||||
int phase_number_ = 0;
|
||||
int entered_ = 0; // Number of threads that have entered this barrier
|
||||
|
||||
// Enter the barrier and wait until all other threads have also
|
||||
// entered the barrier. Returns iff this is the last thread to
|
||||
// enter the barrier.
|
||||
bool createBarrier(MutexLock& ml) REQUIRES(lock_) {
|
||||
CHECK_LT(entered_, running_threads_);
|
||||
entered_++;
|
||||
if (entered_ < running_threads_) {
|
||||
// Wait for all threads to enter
|
||||
int phase_number_cp = phase_number_;
|
||||
auto cb = [this, phase_number_cp]() {
|
||||
return this->phase_number_ > phase_number_cp ||
|
||||
entered_ == running_threads_; // A thread has aborted in error
|
||||
};
|
||||
phase_condition_.wait(ml.native_handle(), cb);
|
||||
if (phase_number_ > phase_number_cp) return false;
|
||||
// else (running_threads_ == entered_) and we are the last thread.
|
||||
}
|
||||
// Last thread has reached the barrier
|
||||
phase_number_++;
|
||||
entered_ = 0;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace benchmark
|
||||
|
||||
#endif // BENCHMARK_MUTEX_H_
|
||||
152
benchmarks/thirdparty/benchmark/src/re.h
vendored
152
benchmarks/thirdparty/benchmark/src/re.h
vendored
@@ -1,152 +0,0 @@
|
||||
// Copyright 2015 Google Inc. All rights reserved.
|
||||
//
|
||||
// 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 BENCHMARK_RE_H_
|
||||
#define BENCHMARK_RE_H_
|
||||
|
||||
#include "internal_macros.h"
|
||||
|
||||
#if !defined(HAVE_STD_REGEX) && \
|
||||
!defined(HAVE_GNU_POSIX_REGEX) && \
|
||||
!defined(HAVE_POSIX_REGEX)
|
||||
// No explicit regex selection; detect based on builtin hints.
|
||||
#if defined(BENCHMARK_OS_LINUX) || defined(BENCHMARK_OS_APPLE)
|
||||
#define HAVE_POSIX_REGEX 1
|
||||
#elif __cplusplus >= 199711L
|
||||
#define HAVE_STD_REGEX 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Prefer C regex libraries when compiling w/o exceptions so that we can
|
||||
// correctly report errors.
|
||||
#if defined(BENCHMARK_HAS_NO_EXCEPTIONS) && \
|
||||
defined(BENCHMARK_HAVE_STD_REGEX) && \
|
||||
(defined(HAVE_GNU_POSIX_REGEX) || defined(HAVE_POSIX_REGEX))
|
||||
#undef HAVE_STD_REGEX
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_STD_REGEX)
|
||||
#include <regex>
|
||||
#elif defined(HAVE_GNU_POSIX_REGEX)
|
||||
#include <gnuregex.h>
|
||||
#elif defined(HAVE_POSIX_REGEX)
|
||||
#include <regex.h>
|
||||
#else
|
||||
#error No regular expression backend was found!
|
||||
#endif
|
||||
#include <string>
|
||||
|
||||
#include "check.h"
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
// A wrapper around the POSIX regular expression API that provides automatic
|
||||
// cleanup
|
||||
class Regex {
|
||||
public:
|
||||
Regex() : init_(false) {}
|
||||
|
||||
~Regex();
|
||||
|
||||
// Compile a regular expression matcher from spec. Returns true on success.
|
||||
//
|
||||
// On failure (and if error is not nullptr), error is populated with a human
|
||||
// readable error message if an error occurs.
|
||||
bool Init(const std::string& spec, std::string* error);
|
||||
|
||||
// Returns whether str matches the compiled regular expression.
|
||||
bool Match(const std::string& str);
|
||||
|
||||
private:
|
||||
bool init_;
|
||||
// Underlying regular expression object
|
||||
#if defined(HAVE_STD_REGEX)
|
||||
std::regex re_;
|
||||
#elif defined(HAVE_POSIX_REGEX) || defined(HAVE_GNU_POSIX_REGEX)
|
||||
regex_t re_;
|
||||
#else
|
||||
#error No regular expression backend implementation available
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(HAVE_STD_REGEX)
|
||||
|
||||
inline bool Regex::Init(const std::string& spec, std::string* error) {
|
||||
#ifdef BENCHMARK_HAS_NO_EXCEPTIONS
|
||||
((void)error); // suppress unused warning
|
||||
#else
|
||||
try {
|
||||
#endif
|
||||
re_ = std::regex(spec, std::regex_constants::extended);
|
||||
init_ = true;
|
||||
#ifndef BENCHMARK_HAS_NO_EXCEPTIONS
|
||||
} catch (const std::regex_error& e) {
|
||||
if (error) {
|
||||
*error = e.what();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return init_;
|
||||
}
|
||||
|
||||
inline Regex::~Regex() {}
|
||||
|
||||
inline bool Regex::Match(const std::string& str) {
|
||||
if (!init_) {
|
||||
return false;
|
||||
}
|
||||
return std::regex_search(str, re_);
|
||||
}
|
||||
|
||||
#else
|
||||
inline bool Regex::Init(const std::string& spec, std::string* error) {
|
||||
int ec = regcomp(&re_, spec.c_str(), REG_EXTENDED | REG_NOSUB);
|
||||
if (ec != 0) {
|
||||
if (error) {
|
||||
size_t needed = regerror(ec, &re_, nullptr, 0);
|
||||
char* errbuf = new char[needed];
|
||||
regerror(ec, &re_, errbuf, needed);
|
||||
|
||||
// regerror returns the number of bytes necessary to null terminate
|
||||
// the string, so we move that when assigning to error.
|
||||
CHECK_NE(needed, 0);
|
||||
error->assign(errbuf, needed - 1);
|
||||
|
||||
delete[] errbuf;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
init_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline Regex::~Regex() {
|
||||
if (init_) {
|
||||
regfree(&re_);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool Regex::Match(const std::string& str) {
|
||||
if (!init_) {
|
||||
return false;
|
||||
}
|
||||
return regexec(&re_, str.c_str(), 0, nullptr, 0) == 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // end namespace benchmark
|
||||
|
||||
#endif // BENCHMARK_RE_H_
|
||||
87
benchmarks/thirdparty/benchmark/src/reporter.cc
vendored
87
benchmarks/thirdparty/benchmark/src/reporter.cc
vendored
@@ -1,87 +0,0 @@
|
||||
// Copyright 2015 Google Inc. All rights reserved.
|
||||
//
|
||||
// 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 "benchmark/benchmark.h"
|
||||
#include "timers.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <iostream>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include "check.h"
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
BenchmarkReporter::BenchmarkReporter()
|
||||
: output_stream_(&std::cout), error_stream_(&std::cerr) {}
|
||||
|
||||
BenchmarkReporter::~BenchmarkReporter() {}
|
||||
|
||||
void BenchmarkReporter::PrintBasicContext(std::ostream *out,
|
||||
Context const &context) {
|
||||
CHECK(out) << "cannot be null";
|
||||
auto &Out = *out;
|
||||
|
||||
Out << LocalDateTimeString() << "\n";
|
||||
|
||||
if (context.executable_name)
|
||||
Out << "Running " << context.executable_name << "\n";
|
||||
|
||||
const CPUInfo &info = context.cpu_info;
|
||||
Out << "Run on (" << info.num_cpus << " X "
|
||||
<< (info.cycles_per_second / 1000000.0) << " MHz CPU "
|
||||
<< ((info.num_cpus > 1) ? "s" : "") << ")\n";
|
||||
if (info.caches.size() != 0) {
|
||||
Out << "CPU Caches:\n";
|
||||
for (auto &CInfo : info.caches) {
|
||||
Out << " L" << CInfo.level << " " << CInfo.type << " "
|
||||
<< (CInfo.size / 1000) << "K";
|
||||
if (CInfo.num_sharing != 0)
|
||||
Out << " (x" << (info.num_cpus / CInfo.num_sharing) << ")";
|
||||
Out << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (info.scaling_enabled) {
|
||||
Out << "***WARNING*** CPU scaling is enabled, the benchmark "
|
||||
"real time measurements may be noisy and will incur extra "
|
||||
"overhead.\n";
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
Out << "***WARNING*** Library was built as DEBUG. Timings may be "
|
||||
"affected.\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
// No initializer because it's already initialized to NULL.
|
||||
const char* BenchmarkReporter::Context::executable_name;
|
||||
|
||||
BenchmarkReporter::Context::Context() : cpu_info(CPUInfo::Get()) {}
|
||||
|
||||
double BenchmarkReporter::Run::GetAdjustedRealTime() const {
|
||||
double new_time = real_accumulated_time * GetTimeUnitMultiplier(time_unit);
|
||||
if (iterations != 0) new_time /= static_cast<double>(iterations);
|
||||
return new_time;
|
||||
}
|
||||
|
||||
double BenchmarkReporter::Run::GetAdjustedCPUTime() const {
|
||||
double new_time = cpu_accumulated_time * GetTimeUnitMultiplier(time_unit);
|
||||
if (iterations != 0) new_time /= static_cast<double>(iterations);
|
||||
return new_time;
|
||||
}
|
||||
|
||||
} // end namespace benchmark
|
||||
51
benchmarks/thirdparty/benchmark/src/sleep.cc
vendored
51
benchmarks/thirdparty/benchmark/src/sleep.cc
vendored
@@ -1,51 +0,0 @@
|
||||
// Copyright 2015 Google Inc. All rights reserved.
|
||||
//
|
||||
// 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 "sleep.h"
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
|
||||
#include "internal_macros.h"
|
||||
|
||||
#ifdef BENCHMARK_OS_WINDOWS
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
namespace benchmark {
|
||||
#ifdef BENCHMARK_OS_WINDOWS
|
||||
// Window's Sleep takes milliseconds argument.
|
||||
void SleepForMilliseconds(int milliseconds) { Sleep(milliseconds); }
|
||||
void SleepForSeconds(double seconds) {
|
||||
SleepForMilliseconds(static_cast<int>(kNumMillisPerSecond * seconds));
|
||||
}
|
||||
#else // BENCHMARK_OS_WINDOWS
|
||||
void SleepForMicroseconds(int microseconds) {
|
||||
struct timespec sleep_time;
|
||||
sleep_time.tv_sec = microseconds / kNumMicrosPerSecond;
|
||||
sleep_time.tv_nsec = (microseconds % kNumMicrosPerSecond) * kNumNanosPerMicro;
|
||||
while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR)
|
||||
; // Ignore signals and wait for the full interval to elapse.
|
||||
}
|
||||
|
||||
void SleepForMilliseconds(int milliseconds) {
|
||||
SleepForMicroseconds(milliseconds * kNumMicrosPerMilli);
|
||||
}
|
||||
|
||||
void SleepForSeconds(double seconds) {
|
||||
SleepForMicroseconds(static_cast<int>(seconds * kNumMicrosPerSecond));
|
||||
}
|
||||
#endif // BENCHMARK_OS_WINDOWS
|
||||
} // end namespace benchmark
|
||||
15
benchmarks/thirdparty/benchmark/src/sleep.h
vendored
15
benchmarks/thirdparty/benchmark/src/sleep.h
vendored
@@ -1,15 +0,0 @@
|
||||
#ifndef BENCHMARK_SLEEP_H_
|
||||
#define BENCHMARK_SLEEP_H_
|
||||
|
||||
namespace benchmark {
|
||||
const int kNumMillisPerSecond = 1000;
|
||||
const int kNumMicrosPerMilli = 1000;
|
||||
const int kNumMicrosPerSecond = kNumMillisPerSecond * 1000;
|
||||
const int kNumNanosPerMicro = 1000;
|
||||
const int kNumNanosPerSecond = kNumNanosPerMicro * kNumMicrosPerSecond;
|
||||
|
||||
void SleepForMilliseconds(int milliseconds);
|
||||
void SleepForSeconds(double seconds);
|
||||
} // end namespace benchmark
|
||||
|
||||
#endif // BENCHMARK_SLEEP_H_
|
||||
178
benchmarks/thirdparty/benchmark/src/statistics.cc
vendored
178
benchmarks/thirdparty/benchmark/src/statistics.cc
vendored
@@ -1,178 +0,0 @@
|
||||
// Copyright 2016 Ismael Jimenez Martinez. All rights reserved.
|
||||
// Copyright 2017 Roman Lebedev. All rights reserved.
|
||||
//
|
||||
// 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 "benchmark/benchmark.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <numeric>
|
||||
#include "check.h"
|
||||
#include "statistics.h"
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
auto StatisticsSum = [](const std::vector<double>& v) {
|
||||
return std::accumulate(v.begin(), v.end(), 0.0);
|
||||
};
|
||||
|
||||
double StatisticsMean(const std::vector<double>& v) {
|
||||
if (v.empty()) return 0.0;
|
||||
return StatisticsSum(v) * (1.0 / v.size());
|
||||
}
|
||||
|
||||
double StatisticsMedian(const std::vector<double>& v) {
|
||||
if (v.size() < 3) return StatisticsMean(v);
|
||||
std::vector<double> copy(v);
|
||||
|
||||
auto center = copy.begin() + v.size() / 2;
|
||||
std::nth_element(copy.begin(), center, copy.end());
|
||||
|
||||
// did we have an odd number of samples?
|
||||
// if yes, then center is the median
|
||||
// it no, then we are looking for the average between center and the value before
|
||||
if(v.size() % 2 == 1)
|
||||
return *center;
|
||||
auto center2 = copy.begin() + v.size() / 2 - 1;
|
||||
std::nth_element(copy.begin(), center2, copy.end());
|
||||
return (*center + *center2) / 2.0;
|
||||
}
|
||||
|
||||
// Return the sum of the squares of this sample set
|
||||
auto SumSquares = [](const std::vector<double>& v) {
|
||||
return std::inner_product(v.begin(), v.end(), v.begin(), 0.0);
|
||||
};
|
||||
|
||||
auto Sqr = [](const double dat) { return dat * dat; };
|
||||
auto Sqrt = [](const double dat) {
|
||||
// Avoid NaN due to imprecision in the calculations
|
||||
if (dat < 0.0) return 0.0;
|
||||
return std::sqrt(dat);
|
||||
};
|
||||
|
||||
double StatisticsStdDev(const std::vector<double>& v) {
|
||||
const auto mean = StatisticsMean(v);
|
||||
if (v.empty()) return mean;
|
||||
|
||||
// Sample standard deviation is undefined for n = 1
|
||||
if (v.size() == 1)
|
||||
return 0.0;
|
||||
|
||||
const double avg_squares = SumSquares(v) * (1.0 / v.size());
|
||||
return Sqrt(v.size() / (v.size() - 1.0) * (avg_squares - Sqr(mean)));
|
||||
}
|
||||
|
||||
std::vector<BenchmarkReporter::Run> ComputeStats(
|
||||
const std::vector<BenchmarkReporter::Run>& reports) {
|
||||
typedef BenchmarkReporter::Run Run;
|
||||
std::vector<Run> results;
|
||||
|
||||
auto error_count =
|
||||
std::count_if(reports.begin(), reports.end(),
|
||||
[](Run const& run) { return run.error_occurred; });
|
||||
|
||||
if (reports.size() - error_count < 2) {
|
||||
// We don't report aggregated data if there was a single run.
|
||||
return results;
|
||||
}
|
||||
|
||||
// Accumulators.
|
||||
std::vector<double> real_accumulated_time_stat;
|
||||
std::vector<double> cpu_accumulated_time_stat;
|
||||
std::vector<double> bytes_per_second_stat;
|
||||
std::vector<double> items_per_second_stat;
|
||||
|
||||
real_accumulated_time_stat.reserve(reports.size());
|
||||
cpu_accumulated_time_stat.reserve(reports.size());
|
||||
bytes_per_second_stat.reserve(reports.size());
|
||||
items_per_second_stat.reserve(reports.size());
|
||||
|
||||
// All repetitions should be run with the same number of iterations so we
|
||||
// can take this information from the first benchmark.
|
||||
int64_t const run_iterations = reports.front().iterations;
|
||||
// create stats for user counters
|
||||
struct CounterStat {
|
||||
Counter c;
|
||||
std::vector<double> s;
|
||||
};
|
||||
std::map< std::string, CounterStat > counter_stats;
|
||||
for(Run const& r : reports) {
|
||||
for(auto const& cnt : r.counters) {
|
||||
auto it = counter_stats.find(cnt.first);
|
||||
if(it == counter_stats.end()) {
|
||||
counter_stats.insert({cnt.first, {cnt.second, std::vector<double>{}}});
|
||||
it = counter_stats.find(cnt.first);
|
||||
it->second.s.reserve(reports.size());
|
||||
} else {
|
||||
CHECK_EQ(counter_stats[cnt.first].c.flags, cnt.second.flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Populate the accumulators.
|
||||
for (Run const& run : reports) {
|
||||
CHECK_EQ(reports[0].benchmark_name, run.benchmark_name);
|
||||
CHECK_EQ(run_iterations, run.iterations);
|
||||
if (run.error_occurred) continue;
|
||||
real_accumulated_time_stat.emplace_back(run.real_accumulated_time);
|
||||
cpu_accumulated_time_stat.emplace_back(run.cpu_accumulated_time);
|
||||
items_per_second_stat.emplace_back(run.items_per_second);
|
||||
bytes_per_second_stat.emplace_back(run.bytes_per_second);
|
||||
// user counters
|
||||
for(auto const& cnt : run.counters) {
|
||||
auto it = counter_stats.find(cnt.first);
|
||||
CHECK_NE(it, counter_stats.end());
|
||||
it->second.s.emplace_back(cnt.second);
|
||||
}
|
||||
}
|
||||
|
||||
// Only add label if it is same for all runs
|
||||
std::string report_label = reports[0].report_label;
|
||||
for (std::size_t i = 1; i < reports.size(); i++) {
|
||||
if (reports[i].report_label != report_label) {
|
||||
report_label = "";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for(const auto& Stat : *reports[0].statistics) {
|
||||
// Get the data from the accumulator to BenchmarkReporter::Run's.
|
||||
Run data;
|
||||
data.benchmark_name = reports[0].benchmark_name + "_" + Stat.name_;
|
||||
data.report_label = report_label;
|
||||
data.iterations = run_iterations;
|
||||
|
||||
data.real_accumulated_time = Stat.compute_(real_accumulated_time_stat);
|
||||
data.cpu_accumulated_time = Stat.compute_(cpu_accumulated_time_stat);
|
||||
data.bytes_per_second = Stat.compute_(bytes_per_second_stat);
|
||||
data.items_per_second = Stat.compute_(items_per_second_stat);
|
||||
|
||||
data.time_unit = reports[0].time_unit;
|
||||
|
||||
// user counters
|
||||
for(auto const& kv : counter_stats) {
|
||||
const auto uc_stat = Stat.compute_(kv.second.s);
|
||||
auto c = Counter(uc_stat, counter_stats[kv.first].c.flags);
|
||||
data.counters[kv.first] = c;
|
||||
}
|
||||
|
||||
results.push_back(data);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
} // end namespace benchmark
|
||||
37
benchmarks/thirdparty/benchmark/src/statistics.h
vendored
37
benchmarks/thirdparty/benchmark/src/statistics.h
vendored
@@ -1,37 +0,0 @@
|
||||
// Copyright 2016 Ismael Jimenez Martinez. All rights reserved.
|
||||
// Copyright 2017 Roman Lebedev. All rights reserved.
|
||||
//
|
||||
// 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 STATISTICS_H_
|
||||
#define STATISTICS_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
// Return a vector containing the mean, median and standard devation information
|
||||
// (and any user-specified info) for the specified list of reports. If 'reports'
|
||||
// contains less than two non-errored runs an empty vector is returned
|
||||
std::vector<BenchmarkReporter::Run> ComputeStats(
|
||||
const std::vector<BenchmarkReporter::Run>& reports);
|
||||
|
||||
double StatisticsMean(const std::vector<double>& v);
|
||||
double StatisticsMedian(const std::vector<double>& v);
|
||||
double StatisticsStdDev(const std::vector<double>& v);
|
||||
|
||||
} // end namespace benchmark
|
||||
|
||||
#endif // STATISTICS_H_
|
||||
172
benchmarks/thirdparty/benchmark/src/string_util.cc
vendored
172
benchmarks/thirdparty/benchmark/src/string_util.cc
vendored
@@ -1,172 +0,0 @@
|
||||
#include "string_util.h"
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
#include "arraysize.h"
|
||||
|
||||
namespace benchmark {
|
||||
namespace {
|
||||
|
||||
// kilo, Mega, Giga, Tera, Peta, Exa, Zetta, Yotta.
|
||||
const char kBigSIUnits[] = "kMGTPEZY";
|
||||
// Kibi, Mebi, Gibi, Tebi, Pebi, Exbi, Zebi, Yobi.
|
||||
const char kBigIECUnits[] = "KMGTPEZY";
|
||||
// milli, micro, nano, pico, femto, atto, zepto, yocto.
|
||||
const char kSmallSIUnits[] = "munpfazy";
|
||||
|
||||
// We require that all three arrays have the same size.
|
||||
static_assert(arraysize(kBigSIUnits) == arraysize(kBigIECUnits),
|
||||
"SI and IEC unit arrays must be the same size");
|
||||
static_assert(arraysize(kSmallSIUnits) == arraysize(kBigSIUnits),
|
||||
"Small SI and Big SI unit arrays must be the same size");
|
||||
|
||||
static const int64_t kUnitsSize = arraysize(kBigSIUnits);
|
||||
|
||||
void ToExponentAndMantissa(double val, double thresh, int precision,
|
||||
double one_k, std::string* mantissa,
|
||||
int64_t* exponent) {
|
||||
std::stringstream mantissa_stream;
|
||||
|
||||
if (val < 0) {
|
||||
mantissa_stream << "-";
|
||||
val = -val;
|
||||
}
|
||||
|
||||
// Adjust threshold so that it never excludes things which can't be rendered
|
||||
// in 'precision' digits.
|
||||
const double adjusted_threshold =
|
||||
std::max(thresh, 1.0 / std::pow(10.0, precision));
|
||||
const double big_threshold = adjusted_threshold * one_k;
|
||||
const double small_threshold = adjusted_threshold;
|
||||
// Values in ]simple_threshold,small_threshold[ will be printed as-is
|
||||
const double simple_threshold = 0.01;
|
||||
|
||||
if (val > big_threshold) {
|
||||
// Positive powers
|
||||
double scaled = val;
|
||||
for (size_t i = 0; i < arraysize(kBigSIUnits); ++i) {
|
||||
scaled /= one_k;
|
||||
if (scaled <= big_threshold) {
|
||||
mantissa_stream << scaled;
|
||||
*exponent = i + 1;
|
||||
*mantissa = mantissa_stream.str();
|
||||
return;
|
||||
}
|
||||
}
|
||||
mantissa_stream << val;
|
||||
*exponent = 0;
|
||||
} else if (val < small_threshold) {
|
||||
// Negative powers
|
||||
if (val < simple_threshold) {
|
||||
double scaled = val;
|
||||
for (size_t i = 0; i < arraysize(kSmallSIUnits); ++i) {
|
||||
scaled *= one_k;
|
||||
if (scaled >= small_threshold) {
|
||||
mantissa_stream << scaled;
|
||||
*exponent = -static_cast<int64_t>(i + 1);
|
||||
*mantissa = mantissa_stream.str();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
mantissa_stream << val;
|
||||
*exponent = 0;
|
||||
} else {
|
||||
mantissa_stream << val;
|
||||
*exponent = 0;
|
||||
}
|
||||
*mantissa = mantissa_stream.str();
|
||||
}
|
||||
|
||||
std::string ExponentToPrefix(int64_t exponent, bool iec) {
|
||||
if (exponent == 0) return "";
|
||||
|
||||
const int64_t index = (exponent > 0 ? exponent - 1 : -exponent - 1);
|
||||
if (index >= kUnitsSize) return "";
|
||||
|
||||
const char* array =
|
||||
(exponent > 0 ? (iec ? kBigIECUnits : kBigSIUnits) : kSmallSIUnits);
|
||||
if (iec)
|
||||
return array[index] + std::string("i");
|
||||
else
|
||||
return std::string(1, array[index]);
|
||||
}
|
||||
|
||||
std::string ToBinaryStringFullySpecified(double value, double threshold,
|
||||
int precision, double one_k = 1024.0) {
|
||||
std::string mantissa;
|
||||
int64_t exponent;
|
||||
ToExponentAndMantissa(value, threshold, precision, one_k, &mantissa,
|
||||
&exponent);
|
||||
return mantissa + ExponentToPrefix(exponent, false);
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
void AppendHumanReadable(int n, std::string* str) {
|
||||
std::stringstream ss;
|
||||
// Round down to the nearest SI prefix.
|
||||
ss << ToBinaryStringFullySpecified(n, 1.0, 0);
|
||||
*str += ss.str();
|
||||
}
|
||||
|
||||
std::string HumanReadableNumber(double n, double one_k) {
|
||||
// 1.1 means that figures up to 1.1k should be shown with the next unit down;
|
||||
// this softens edge effects.
|
||||
// 1 means that we should show one decimal place of precision.
|
||||
return ToBinaryStringFullySpecified(n, 1.1, 1, one_k);
|
||||
}
|
||||
|
||||
std::string StrFormatImp(const char* msg, va_list args) {
|
||||
// we might need a second shot at this, so pre-emptivly make a copy
|
||||
va_list args_cp;
|
||||
va_copy(args_cp, args);
|
||||
|
||||
// TODO(ericwf): use std::array for first attempt to avoid one memory
|
||||
// allocation guess what the size might be
|
||||
std::array<char, 256> local_buff;
|
||||
std::size_t size = local_buff.size();
|
||||
// 2015-10-08: vsnprintf is used instead of snd::vsnprintf due to a limitation
|
||||
// in the android-ndk
|
||||
auto ret = vsnprintf(local_buff.data(), size, msg, args_cp);
|
||||
|
||||
va_end(args_cp);
|
||||
|
||||
// handle empty expansion
|
||||
if (ret == 0) return std::string{};
|
||||
if (static_cast<std::size_t>(ret) < size)
|
||||
return std::string(local_buff.data());
|
||||
|
||||
// we did not provide a long enough buffer on our first attempt.
|
||||
// add 1 to size to account for null-byte in size cast to prevent overflow
|
||||
size = static_cast<std::size_t>(ret) + 1;
|
||||
auto buff_ptr = std::unique_ptr<char[]>(new char[size]);
|
||||
// 2015-10-08: vsnprintf is used instead of snd::vsnprintf due to a limitation
|
||||
// in the android-ndk
|
||||
ret = vsnprintf(buff_ptr.get(), size, msg, args);
|
||||
return std::string(buff_ptr.get());
|
||||
}
|
||||
|
||||
std::string StrFormat(const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
std::string tmp = StrFormatImp(format, args);
|
||||
va_end(args);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void ReplaceAll(std::string* str, const std::string& from,
|
||||
const std::string& to) {
|
||||
std::size_t start = 0;
|
||||
while ((start = str->find(from, start)) != std::string::npos) {
|
||||
str->replace(start, from.length(), to);
|
||||
start += to.length();
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace benchmark
|
||||
@@ -1,40 +0,0 @@
|
||||
#ifndef BENCHMARK_STRING_UTIL_H_
|
||||
#define BENCHMARK_STRING_UTIL_H_
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include "internal_macros.h"
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
void AppendHumanReadable(int n, std::string* str);
|
||||
|
||||
std::string HumanReadableNumber(double n, double one_k = 1024.0);
|
||||
|
||||
std::string StrFormat(const char* format, ...);
|
||||
|
||||
inline std::ostream& StrCatImp(std::ostream& out) BENCHMARK_NOEXCEPT {
|
||||
return out;
|
||||
}
|
||||
|
||||
template <class First, class... Rest>
|
||||
inline std::ostream& StrCatImp(std::ostream& out, First&& f,
|
||||
Rest&&... rest) {
|
||||
out << std::forward<First>(f);
|
||||
return StrCatImp(out, std::forward<Rest>(rest)...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
inline std::string StrCat(Args&&... args) {
|
||||
std::ostringstream ss;
|
||||
StrCatImp(ss, std::forward<Args>(args)...);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void ReplaceAll(std::string* str, const std::string& from,
|
||||
const std::string& to);
|
||||
|
||||
} // end namespace benchmark
|
||||
|
||||
#endif // BENCHMARK_STRING_UTIL_H_
|
||||
587
benchmarks/thirdparty/benchmark/src/sysinfo.cc
vendored
587
benchmarks/thirdparty/benchmark/src/sysinfo.cc
vendored
@@ -1,587 +0,0 @@
|
||||
// Copyright 2015 Google Inc. All rights reserved.
|
||||
//
|
||||
// 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 "internal_macros.h"
|
||||
|
||||
#ifdef BENCHMARK_OS_WINDOWS
|
||||
#include <Shlwapi.h>
|
||||
#undef StrCat // Don't let StrCat in string_util.h be renamed to lstrcatA
|
||||
#include <VersionHelpers.h>
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <fcntl.h>
|
||||
#ifndef BENCHMARK_OS_FUCHSIA
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h> // this header must be included before 'sys/sysctl.h' to avoid compilation error on FreeBSD
|
||||
#include <unistd.h>
|
||||
#if defined BENCHMARK_OS_FREEBSD || defined BENCHMARK_OS_MACOSX || \
|
||||
defined BENCHMARK_OS_NETBSD || defined BENCHMARK_OS_OPENBSD
|
||||
#define BENCHMARK_HAS_SYSCTL
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
#endif
|
||||
#if defined(BENCHMARK_OS_SOLARIS)
|
||||
#include <kstat.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <bitset>
|
||||
#include <cerrno>
|
||||
#include <climits>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
#include "check.h"
|
||||
#include "cycleclock.h"
|
||||
#include "internal_macros.h"
|
||||
#include "log.h"
|
||||
#include "sleep.h"
|
||||
#include "string_util.h"
|
||||
|
||||
namespace benchmark {
|
||||
namespace {
|
||||
|
||||
void PrintImp(std::ostream& out) { out << std::endl; }
|
||||
|
||||
template <class First, class... Rest>
|
||||
void PrintImp(std::ostream& out, First&& f, Rest&&... rest) {
|
||||
out << std::forward<First>(f);
|
||||
PrintImp(out, std::forward<Rest>(rest)...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
BENCHMARK_NORETURN void PrintErrorAndDie(Args&&... args) {
|
||||
PrintImp(std::cerr, std::forward<Args>(args)...);
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#ifdef BENCHMARK_HAS_SYSCTL
|
||||
|
||||
/// ValueUnion - A type used to correctly alias the byte-for-byte output of
|
||||
/// `sysctl` with the result type it's to be interpreted as.
|
||||
struct ValueUnion {
|
||||
union DataT {
|
||||
uint32_t uint32_value;
|
||||
uint64_t uint64_value;
|
||||
// For correct aliasing of union members from bytes.
|
||||
char bytes[8];
|
||||
};
|
||||
using DataPtr = std::unique_ptr<DataT, decltype(&std::free)>;
|
||||
|
||||
// The size of the data union member + its trailing array size.
|
||||
size_t Size;
|
||||
DataPtr Buff;
|
||||
|
||||
public:
|
||||
ValueUnion() : Size(0), Buff(nullptr, &std::free) {}
|
||||
|
||||
explicit ValueUnion(size_t BuffSize)
|
||||
: Size(sizeof(DataT) + BuffSize),
|
||||
Buff(::new (std::malloc(Size)) DataT(), &std::free) {}
|
||||
|
||||
ValueUnion(ValueUnion&& other) = default;
|
||||
|
||||
explicit operator bool() const { return bool(Buff); }
|
||||
|
||||
char* data() const { return Buff->bytes; }
|
||||
|
||||
std::string GetAsString() const { return std::string(data()); }
|
||||
|
||||
int64_t GetAsInteger() const {
|
||||
if (Size == sizeof(Buff->uint32_value))
|
||||
return static_cast<int32_t>(Buff->uint32_value);
|
||||
else if (Size == sizeof(Buff->uint64_value))
|
||||
return static_cast<int64_t>(Buff->uint64_value);
|
||||
BENCHMARK_UNREACHABLE();
|
||||
}
|
||||
|
||||
uint64_t GetAsUnsigned() const {
|
||||
if (Size == sizeof(Buff->uint32_value))
|
||||
return Buff->uint32_value;
|
||||
else if (Size == sizeof(Buff->uint64_value))
|
||||
return Buff->uint64_value;
|
||||
BENCHMARK_UNREACHABLE();
|
||||
}
|
||||
|
||||
template <class T, int N>
|
||||
std::array<T, N> GetAsArray() {
|
||||
const int ArrSize = sizeof(T) * N;
|
||||
CHECK_LE(ArrSize, Size);
|
||||
std::array<T, N> Arr;
|
||||
std::memcpy(Arr.data(), data(), ArrSize);
|
||||
return Arr;
|
||||
}
|
||||
};
|
||||
|
||||
ValueUnion GetSysctlImp(std::string const& Name) {
|
||||
#if defined BENCHMARK_OS_OPENBSD
|
||||
int mib[2];
|
||||
|
||||
mib[0] = CTL_HW;
|
||||
if ((Name == "hw.ncpu") || (Name == "hw.cpuspeed")){
|
||||
ValueUnion buff(sizeof(int));
|
||||
|
||||
if (Name == "hw.ncpu") {
|
||||
mib[1] = HW_NCPU;
|
||||
} else {
|
||||
mib[1] = HW_CPUSPEED;
|
||||
}
|
||||
|
||||
if (sysctl(mib, 2, buff.data(), &buff.Size, nullptr, 0) == -1) {
|
||||
return ValueUnion();
|
||||
}
|
||||
return buff;
|
||||
}
|
||||
return ValueUnion();
|
||||
#else
|
||||
size_t CurBuffSize = 0;
|
||||
if (sysctlbyname(Name.c_str(), nullptr, &CurBuffSize, nullptr, 0) == -1)
|
||||
return ValueUnion();
|
||||
|
||||
ValueUnion buff(CurBuffSize);
|
||||
if (sysctlbyname(Name.c_str(), buff.data(), &buff.Size, nullptr, 0) == 0)
|
||||
return buff;
|
||||
return ValueUnion();
|
||||
#endif
|
||||
}
|
||||
|
||||
BENCHMARK_MAYBE_UNUSED
|
||||
bool GetSysctl(std::string const& Name, std::string* Out) {
|
||||
Out->clear();
|
||||
auto Buff = GetSysctlImp(Name);
|
||||
if (!Buff) return false;
|
||||
Out->assign(Buff.data());
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class Tp,
|
||||
class = typename std::enable_if<std::is_integral<Tp>::value>::type>
|
||||
bool GetSysctl(std::string const& Name, Tp* Out) {
|
||||
*Out = 0;
|
||||
auto Buff = GetSysctlImp(Name);
|
||||
if (!Buff) return false;
|
||||
*Out = static_cast<Tp>(Buff.GetAsUnsigned());
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class Tp, size_t N>
|
||||
bool GetSysctl(std::string const& Name, std::array<Tp, N>* Out) {
|
||||
auto Buff = GetSysctlImp(Name);
|
||||
if (!Buff) return false;
|
||||
*Out = Buff.GetAsArray<Tp, N>();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class ArgT>
|
||||
bool ReadFromFile(std::string const& fname, ArgT* arg) {
|
||||
*arg = ArgT();
|
||||
std::ifstream f(fname.c_str());
|
||||
if (!f.is_open()) return false;
|
||||
f >> *arg;
|
||||
return f.good();
|
||||
}
|
||||
|
||||
bool CpuScalingEnabled(int num_cpus) {
|
||||
// We don't have a valid CPU count, so don't even bother.
|
||||
if (num_cpus <= 0) return false;
|
||||
#ifndef BENCHMARK_OS_WINDOWS
|
||||
// On Linux, the CPUfreq subsystem exposes CPU information as files on the
|
||||
// local file system. If reading the exported files fails, then we may not be
|
||||
// running on Linux, so we silently ignore all the read errors.
|
||||
std::string res;
|
||||
for (int cpu = 0; cpu < num_cpus; ++cpu) {
|
||||
std::string governor_file =
|
||||
StrCat("/sys/devices/system/cpu/cpu", cpu, "/cpufreq/scaling_governor");
|
||||
if (ReadFromFile(governor_file, &res) && res != "performance") return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
int CountSetBitsInCPUMap(std::string Val) {
|
||||
auto CountBits = [](std::string Part) {
|
||||
using CPUMask = std::bitset<sizeof(std::uintptr_t) * CHAR_BIT>;
|
||||
Part = "0x" + Part;
|
||||
CPUMask Mask(std::stoul(Part, nullptr, 16));
|
||||
return static_cast<int>(Mask.count());
|
||||
};
|
||||
size_t Pos;
|
||||
int total = 0;
|
||||
while ((Pos = Val.find(',')) != std::string::npos) {
|
||||
total += CountBits(Val.substr(0, Pos));
|
||||
Val = Val.substr(Pos + 1);
|
||||
}
|
||||
if (!Val.empty()) {
|
||||
total += CountBits(Val);
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
BENCHMARK_MAYBE_UNUSED
|
||||
std::vector<CPUInfo::CacheInfo> GetCacheSizesFromKVFS() {
|
||||
std::vector<CPUInfo::CacheInfo> res;
|
||||
std::string dir = "/sys/devices/system/cpu/cpu0/cache/";
|
||||
int Idx = 0;
|
||||
while (true) {
|
||||
CPUInfo::CacheInfo info;
|
||||
std::string FPath = StrCat(dir, "index", Idx++, "/");
|
||||
std::ifstream f(StrCat(FPath, "size").c_str());
|
||||
if (!f.is_open()) break;
|
||||
std::string suffix;
|
||||
f >> info.size;
|
||||
if (f.fail())
|
||||
PrintErrorAndDie("Failed while reading file '", FPath, "size'");
|
||||
if (f.good()) {
|
||||
f >> suffix;
|
||||
if (f.bad())
|
||||
PrintErrorAndDie(
|
||||
"Invalid cache size format: failed to read size suffix");
|
||||
else if (f && suffix != "K")
|
||||
PrintErrorAndDie("Invalid cache size format: Expected bytes ", suffix);
|
||||
else if (suffix == "K")
|
||||
info.size *= 1000;
|
||||
}
|
||||
if (!ReadFromFile(StrCat(FPath, "type"), &info.type))
|
||||
PrintErrorAndDie("Failed to read from file ", FPath, "type");
|
||||
if (!ReadFromFile(StrCat(FPath, "level"), &info.level))
|
||||
PrintErrorAndDie("Failed to read from file ", FPath, "level");
|
||||
std::string map_str;
|
||||
if (!ReadFromFile(StrCat(FPath, "shared_cpu_map"), &map_str))
|
||||
PrintErrorAndDie("Failed to read from file ", FPath, "shared_cpu_map");
|
||||
info.num_sharing = CountSetBitsInCPUMap(map_str);
|
||||
res.push_back(info);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifdef BENCHMARK_OS_MACOSX
|
||||
std::vector<CPUInfo::CacheInfo> GetCacheSizesMacOSX() {
|
||||
std::vector<CPUInfo::CacheInfo> res;
|
||||
std::array<uint64_t, 4> CacheCounts{{0, 0, 0, 0}};
|
||||
GetSysctl("hw.cacheconfig", &CacheCounts);
|
||||
|
||||
struct {
|
||||
std::string name;
|
||||
std::string type;
|
||||
int level;
|
||||
size_t num_sharing;
|
||||
} Cases[] = {{"hw.l1dcachesize", "Data", 1, CacheCounts[1]},
|
||||
{"hw.l1icachesize", "Instruction", 1, CacheCounts[1]},
|
||||
{"hw.l2cachesize", "Unified", 2, CacheCounts[2]},
|
||||
{"hw.l3cachesize", "Unified", 3, CacheCounts[3]}};
|
||||
for (auto& C : Cases) {
|
||||
int val;
|
||||
if (!GetSysctl(C.name, &val)) continue;
|
||||
CPUInfo::CacheInfo info;
|
||||
info.type = C.type;
|
||||
info.level = C.level;
|
||||
info.size = val;
|
||||
info.num_sharing = static_cast<int>(C.num_sharing);
|
||||
res.push_back(std::move(info));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#elif defined(BENCHMARK_OS_WINDOWS)
|
||||
std::vector<CPUInfo::CacheInfo> GetCacheSizesWindows() {
|
||||
std::vector<CPUInfo::CacheInfo> res;
|
||||
DWORD buffer_size = 0;
|
||||
using PInfo = SYSTEM_LOGICAL_PROCESSOR_INFORMATION;
|
||||
using CInfo = CACHE_DESCRIPTOR;
|
||||
|
||||
using UPtr = std::unique_ptr<PInfo, decltype(&std::free)>;
|
||||
GetLogicalProcessorInformation(nullptr, &buffer_size);
|
||||
UPtr buff((PInfo*)malloc(buffer_size), &std::free);
|
||||
if (!GetLogicalProcessorInformation(buff.get(), &buffer_size))
|
||||
PrintErrorAndDie("Failed during call to GetLogicalProcessorInformation: ",
|
||||
GetLastError());
|
||||
|
||||
PInfo* it = buff.get();
|
||||
PInfo* end = buff.get() + (buffer_size / sizeof(PInfo));
|
||||
|
||||
for (; it != end; ++it) {
|
||||
if (it->Relationship != RelationCache) continue;
|
||||
using BitSet = std::bitset<sizeof(ULONG_PTR) * CHAR_BIT>;
|
||||
BitSet B(it->ProcessorMask);
|
||||
// To prevent duplicates, only consider caches where CPU 0 is specified
|
||||
if (!B.test(0)) continue;
|
||||
CInfo* Cache = &it->Cache;
|
||||
CPUInfo::CacheInfo C;
|
||||
C.num_sharing = static_cast<int>(B.count());
|
||||
C.level = Cache->Level;
|
||||
C.size = Cache->Size;
|
||||
switch (Cache->Type) {
|
||||
case CacheUnified:
|
||||
C.type = "Unified";
|
||||
break;
|
||||
case CacheInstruction:
|
||||
C.type = "Instruction";
|
||||
break;
|
||||
case CacheData:
|
||||
C.type = "Data";
|
||||
break;
|
||||
case CacheTrace:
|
||||
C.type = "Trace";
|
||||
break;
|
||||
default:
|
||||
C.type = "Unknown";
|
||||
break;
|
||||
}
|
||||
res.push_back(C);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::vector<CPUInfo::CacheInfo> GetCacheSizes() {
|
||||
#ifdef BENCHMARK_OS_MACOSX
|
||||
return GetCacheSizesMacOSX();
|
||||
#elif defined(BENCHMARK_OS_WINDOWS)
|
||||
return GetCacheSizesWindows();
|
||||
#else
|
||||
return GetCacheSizesFromKVFS();
|
||||
#endif
|
||||
}
|
||||
|
||||
int GetNumCPUs() {
|
||||
#ifdef BENCHMARK_HAS_SYSCTL
|
||||
int NumCPU = -1;
|
||||
if (GetSysctl("hw.ncpu", &NumCPU)) return NumCPU;
|
||||
fprintf(stderr, "Err: %s\n", strerror(errno));
|
||||
std::exit(EXIT_FAILURE);
|
||||
#elif defined(BENCHMARK_OS_WINDOWS)
|
||||
SYSTEM_INFO sysinfo;
|
||||
// Use memset as opposed to = {} to avoid GCC missing initializer false
|
||||
// positives.
|
||||
std::memset(&sysinfo, 0, sizeof(SYSTEM_INFO));
|
||||
GetSystemInfo(&sysinfo);
|
||||
return sysinfo.dwNumberOfProcessors; // number of logical
|
||||
// processors in the current
|
||||
// group
|
||||
#elif defined(BENCHMARK_OS_SOLARIS)
|
||||
// Returns -1 in case of a failure.
|
||||
int NumCPU = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
if (NumCPU < 0) {
|
||||
fprintf(stderr,
|
||||
"sysconf(_SC_NPROCESSORS_ONLN) failed with error: %s\n",
|
||||
strerror(errno));
|
||||
}
|
||||
return NumCPU;
|
||||
#else
|
||||
int NumCPUs = 0;
|
||||
int MaxID = -1;
|
||||
std::ifstream f("/proc/cpuinfo");
|
||||
if (!f.is_open()) {
|
||||
std::cerr << "failed to open /proc/cpuinfo\n";
|
||||
return -1;
|
||||
}
|
||||
const std::string Key = "processor";
|
||||
std::string ln;
|
||||
while (std::getline(f, ln)) {
|
||||
if (ln.empty()) continue;
|
||||
size_t SplitIdx = ln.find(':');
|
||||
std::string value;
|
||||
if (SplitIdx != std::string::npos) value = ln.substr(SplitIdx + 1);
|
||||
if (ln.size() >= Key.size() && ln.compare(0, Key.size(), Key) == 0) {
|
||||
NumCPUs++;
|
||||
if (!value.empty()) {
|
||||
int CurID = std::stoi(value);
|
||||
MaxID = std::max(CurID, MaxID);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (f.bad()) {
|
||||
std::cerr << "Failure reading /proc/cpuinfo\n";
|
||||
return -1;
|
||||
}
|
||||
if (!f.eof()) {
|
||||
std::cerr << "Failed to read to end of /proc/cpuinfo\n";
|
||||
return -1;
|
||||
}
|
||||
f.close();
|
||||
|
||||
if ((MaxID + 1) != NumCPUs) {
|
||||
fprintf(stderr,
|
||||
"CPU ID assignments in /proc/cpuinfo seem messed up."
|
||||
" This is usually caused by a bad BIOS.\n");
|
||||
}
|
||||
return NumCPUs;
|
||||
#endif
|
||||
BENCHMARK_UNREACHABLE();
|
||||
}
|
||||
|
||||
double GetCPUCyclesPerSecond() {
|
||||
#if defined BENCHMARK_OS_LINUX || defined BENCHMARK_OS_CYGWIN
|
||||
long freq;
|
||||
|
||||
// If the kernel is exporting the tsc frequency use that. There are issues
|
||||
// where cpuinfo_max_freq cannot be relied on because the BIOS may be
|
||||
// exporintg an invalid p-state (on x86) or p-states may be used to put the
|
||||
// processor in a new mode (turbo mode). Essentially, those frequencies
|
||||
// cannot always be relied upon. The same reasons apply to /proc/cpuinfo as
|
||||
// well.
|
||||
if (ReadFromFile("/sys/devices/system/cpu/cpu0/tsc_freq_khz", &freq)
|
||||
// If CPU scaling is in effect, we want to use the *maximum* frequency,
|
||||
// not whatever CPU speed some random processor happens to be using now.
|
||||
|| ReadFromFile("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq",
|
||||
&freq)) {
|
||||
// The value is in kHz (as the file name suggests). For example, on a
|
||||
// 2GHz warpstation, the file contains the value "2000000".
|
||||
return freq * 1000.0;
|
||||
}
|
||||
|
||||
const double error_value = -1;
|
||||
double bogo_clock = error_value;
|
||||
|
||||
std::ifstream f("/proc/cpuinfo");
|
||||
if (!f.is_open()) {
|
||||
std::cerr << "failed to open /proc/cpuinfo\n";
|
||||
return error_value;
|
||||
}
|
||||
|
||||
auto startsWithKey = [](std::string const& Value, std::string const& Key) {
|
||||
if (Key.size() > Value.size()) return false;
|
||||
auto Cmp = [&](char X, char Y) {
|
||||
return std::tolower(X) == std::tolower(Y);
|
||||
};
|
||||
return std::equal(Key.begin(), Key.end(), Value.begin(), Cmp);
|
||||
};
|
||||
|
||||
std::string ln;
|
||||
while (std::getline(f, ln)) {
|
||||
if (ln.empty()) continue;
|
||||
size_t SplitIdx = ln.find(':');
|
||||
std::string value;
|
||||
if (SplitIdx != std::string::npos) value = ln.substr(SplitIdx + 1);
|
||||
// When parsing the "cpu MHz" and "bogomips" (fallback) entries, we only
|
||||
// accept positive values. Some environments (virtual machines) report zero,
|
||||
// which would cause infinite looping in WallTime_Init.
|
||||
if (startsWithKey(ln, "cpu MHz")) {
|
||||
if (!value.empty()) {
|
||||
double cycles_per_second = std::stod(value) * 1000000.0;
|
||||
if (cycles_per_second > 0) return cycles_per_second;
|
||||
}
|
||||
} else if (startsWithKey(ln, "bogomips")) {
|
||||
if (!value.empty()) {
|
||||
bogo_clock = std::stod(value) * 1000000.0;
|
||||
if (bogo_clock < 0.0) bogo_clock = error_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (f.bad()) {
|
||||
std::cerr << "Failure reading /proc/cpuinfo\n";
|
||||
return error_value;
|
||||
}
|
||||
if (!f.eof()) {
|
||||
std::cerr << "Failed to read to end of /proc/cpuinfo\n";
|
||||
return error_value;
|
||||
}
|
||||
f.close();
|
||||
// If we found the bogomips clock, but nothing better, we'll use it (but
|
||||
// we're not happy about it); otherwise, fallback to the rough estimation
|
||||
// below.
|
||||
if (bogo_clock >= 0.0) return bogo_clock;
|
||||
|
||||
#elif defined BENCHMARK_HAS_SYSCTL
|
||||
constexpr auto* FreqStr =
|
||||
#if defined(BENCHMARK_OS_FREEBSD) || defined(BENCHMARK_OS_NETBSD)
|
||||
"machdep.tsc_freq";
|
||||
#elif defined BENCHMARK_OS_OPENBSD
|
||||
"hw.cpuspeed";
|
||||
#else
|
||||
"hw.cpufrequency";
|
||||
#endif
|
||||
unsigned long long hz = 0;
|
||||
#if defined BENCHMARK_OS_OPENBSD
|
||||
if (GetSysctl(FreqStr, &hz)) return hz * 1000000;
|
||||
#else
|
||||
if (GetSysctl(FreqStr, &hz)) return hz;
|
||||
#endif
|
||||
fprintf(stderr, "Unable to determine clock rate from sysctl: %s: %s\n",
|
||||
FreqStr, strerror(errno));
|
||||
|
||||
#elif defined BENCHMARK_OS_WINDOWS
|
||||
// In NT, read MHz from the registry. If we fail to do so or we're in win9x
|
||||
// then make a crude estimate.
|
||||
DWORD data, data_size = sizeof(data);
|
||||
if (IsWindowsXPOrGreater() &&
|
||||
SUCCEEDED(
|
||||
SHGetValueA(HKEY_LOCAL_MACHINE,
|
||||
"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",
|
||||
"~MHz", nullptr, &data, &data_size)))
|
||||
return static_cast<double>((int64_t)data *
|
||||
(int64_t)(1000 * 1000)); // was mhz
|
||||
#elif defined (BENCHMARK_OS_SOLARIS)
|
||||
kstat_ctl_t *kc = kstat_open();
|
||||
if (!kc) {
|
||||
std::cerr << "failed to open /dev/kstat\n";
|
||||
return -1;
|
||||
}
|
||||
kstat_t *ksp = kstat_lookup(kc, (char*)"cpu_info", -1, (char*)"cpu_info0");
|
||||
if (!ksp) {
|
||||
std::cerr << "failed to lookup in /dev/kstat\n";
|
||||
return -1;
|
||||
}
|
||||
if (kstat_read(kc, ksp, NULL) < 0) {
|
||||
std::cerr << "failed to read from /dev/kstat\n";
|
||||
return -1;
|
||||
}
|
||||
kstat_named_t *knp =
|
||||
(kstat_named_t*)kstat_data_lookup(ksp, (char*)"current_clock_Hz");
|
||||
if (!knp) {
|
||||
std::cerr << "failed to lookup data in /dev/kstat\n";
|
||||
return -1;
|
||||
}
|
||||
if (knp->data_type != KSTAT_DATA_UINT64) {
|
||||
std::cerr << "current_clock_Hz is of unexpected data type: "
|
||||
<< knp->data_type << "\n";
|
||||
return -1;
|
||||
}
|
||||
double clock_hz = knp->value.ui64;
|
||||
kstat_close(kc);
|
||||
return clock_hz;
|
||||
#endif
|
||||
// If we've fallen through, attempt to roughly estimate the CPU clock rate.
|
||||
const int estimate_time_ms = 1000;
|
||||
const auto start_ticks = cycleclock::Now();
|
||||
SleepForMilliseconds(estimate_time_ms);
|
||||
return static_cast<double>(cycleclock::Now() - start_ticks);
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
const CPUInfo& CPUInfo::Get() {
|
||||
static const CPUInfo* info = new CPUInfo();
|
||||
return *info;
|
||||
}
|
||||
|
||||
CPUInfo::CPUInfo()
|
||||
: num_cpus(GetNumCPUs()),
|
||||
cycles_per_second(GetCPUCyclesPerSecond()),
|
||||
caches(GetCacheSizes()),
|
||||
scaling_enabled(CpuScalingEnabled(num_cpus)) {}
|
||||
|
||||
} // end namespace benchmark
|
||||
@@ -1,66 +0,0 @@
|
||||
#ifndef BENCHMARK_THREAD_MANAGER_H
|
||||
#define BENCHMARK_THREAD_MANAGER_H
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
#include "mutex.h"
|
||||
|
||||
namespace benchmark {
|
||||
namespace internal {
|
||||
|
||||
class ThreadManager {
|
||||
public:
|
||||
ThreadManager(int num_threads)
|
||||
: alive_threads_(num_threads), start_stop_barrier_(num_threads) {}
|
||||
|
||||
Mutex& GetBenchmarkMutex() const RETURN_CAPABILITY(benchmark_mutex_) {
|
||||
return benchmark_mutex_;
|
||||
}
|
||||
|
||||
bool StartStopBarrier() EXCLUDES(end_cond_mutex_) {
|
||||
return start_stop_barrier_.wait();
|
||||
}
|
||||
|
||||
void NotifyThreadComplete() EXCLUDES(end_cond_mutex_) {
|
||||
start_stop_barrier_.removeThread();
|
||||
if (--alive_threads_ == 0) {
|
||||
MutexLock lock(end_cond_mutex_);
|
||||
end_condition_.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
void WaitForAllThreads() EXCLUDES(end_cond_mutex_) {
|
||||
MutexLock lock(end_cond_mutex_);
|
||||
end_condition_.wait(lock.native_handle(),
|
||||
[this]() { return alive_threads_ == 0; });
|
||||
}
|
||||
|
||||
public:
|
||||
struct Result {
|
||||
int64_t iterations = 0;
|
||||
double real_time_used = 0;
|
||||
double cpu_time_used = 0;
|
||||
double manual_time_used = 0;
|
||||
int64_t bytes_processed = 0;
|
||||
int64_t items_processed = 0;
|
||||
int64_t complexity_n = 0;
|
||||
std::string report_label_;
|
||||
std::string error_message_;
|
||||
bool has_error_ = false;
|
||||
UserCounters counters;
|
||||
};
|
||||
GUARDED_BY(GetBenchmarkMutex()) Result results;
|
||||
|
||||
private:
|
||||
mutable Mutex benchmark_mutex_;
|
||||
std::atomic<int> alive_threads_;
|
||||
Barrier start_stop_barrier_;
|
||||
Mutex end_cond_mutex_;
|
||||
Condition end_condition_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace benchmark
|
||||
|
||||
#endif // BENCHMARK_THREAD_MANAGER_H
|
||||
@@ -1,69 +0,0 @@
|
||||
#ifndef BENCHMARK_THREAD_TIMER_H
|
||||
#define BENCHMARK_THREAD_TIMER_H
|
||||
|
||||
#include "check.h"
|
||||
#include "timers.h"
|
||||
|
||||
namespace benchmark {
|
||||
namespace internal {
|
||||
|
||||
class ThreadTimer {
|
||||
public:
|
||||
ThreadTimer() = default;
|
||||
|
||||
// Called by each thread
|
||||
void StartTimer() {
|
||||
running_ = true;
|
||||
start_real_time_ = ChronoClockNow();
|
||||
start_cpu_time_ = ThreadCPUUsage();
|
||||
}
|
||||
|
||||
// Called by each thread
|
||||
void StopTimer() {
|
||||
CHECK(running_);
|
||||
running_ = false;
|
||||
real_time_used_ += ChronoClockNow() - start_real_time_;
|
||||
// Floating point error can result in the subtraction producing a negative
|
||||
// time. Guard against that.
|
||||
cpu_time_used_ += std::max<double>(ThreadCPUUsage() - start_cpu_time_, 0);
|
||||
}
|
||||
|
||||
// Called by each thread
|
||||
void SetIterationTime(double seconds) { manual_time_used_ += seconds; }
|
||||
|
||||
bool running() const { return running_; }
|
||||
|
||||
// REQUIRES: timer is not running
|
||||
double real_time_used() {
|
||||
CHECK(!running_);
|
||||
return real_time_used_;
|
||||
}
|
||||
|
||||
// REQUIRES: timer is not running
|
||||
double cpu_time_used() {
|
||||
CHECK(!running_);
|
||||
return cpu_time_used_;
|
||||
}
|
||||
|
||||
// REQUIRES: timer is not running
|
||||
double manual_time_used() {
|
||||
CHECK(!running_);
|
||||
return manual_time_used_;
|
||||
}
|
||||
|
||||
private:
|
||||
bool running_ = false; // Is the timer running
|
||||
double start_real_time_ = 0; // If running_
|
||||
double start_cpu_time_ = 0; // If running_
|
||||
|
||||
// Accumulated time so far (does not contain current slice if running_)
|
||||
double real_time_used_ = 0;
|
||||
double cpu_time_used_ = 0;
|
||||
// Manually set iteration time. User sets this with SetIterationTime(seconds).
|
||||
double manual_time_used_ = 0;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace benchmark
|
||||
|
||||
#endif // BENCHMARK_THREAD_TIMER_H
|
||||
217
benchmarks/thirdparty/benchmark/src/timers.cc
vendored
217
benchmarks/thirdparty/benchmark/src/timers.cc
vendored
@@ -1,217 +0,0 @@
|
||||
// Copyright 2015 Google Inc. All rights reserved.
|
||||
//
|
||||
// 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 "timers.h"
|
||||
#include "internal_macros.h"
|
||||
|
||||
#ifdef BENCHMARK_OS_WINDOWS
|
||||
#include <Shlwapi.h>
|
||||
#undef StrCat // Don't let StrCat in string_util.h be renamed to lstrcatA
|
||||
#include <VersionHelpers.h>
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <fcntl.h>
|
||||
#ifndef BENCHMARK_OS_FUCHSIA
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h> // this header must be included before 'sys/sysctl.h' to avoid compilation error on FreeBSD
|
||||
#include <unistd.h>
|
||||
#if defined BENCHMARK_OS_FREEBSD || defined BENCHMARK_OS_MACOSX
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
#if defined(BENCHMARK_OS_MACOSX)
|
||||
#include <mach/mach_init.h>
|
||||
#include <mach/mach_port.h>
|
||||
#include <mach/thread_act.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef BENCHMARK_OS_EMSCRIPTEN
|
||||
#include <emscripten.h>
|
||||
#endif
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <mutex>
|
||||
|
||||
#include "check.h"
|
||||
#include "log.h"
|
||||
#include "sleep.h"
|
||||
#include "string_util.h"
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
// Suppress unused warnings on helper functions.
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
#if defined(BENCHMARK_OS_WINDOWS)
|
||||
double MakeTime(FILETIME const& kernel_time, FILETIME const& user_time) {
|
||||
ULARGE_INTEGER kernel;
|
||||
ULARGE_INTEGER user;
|
||||
kernel.HighPart = kernel_time.dwHighDateTime;
|
||||
kernel.LowPart = kernel_time.dwLowDateTime;
|
||||
user.HighPart = user_time.dwHighDateTime;
|
||||
user.LowPart = user_time.dwLowDateTime;
|
||||
return (static_cast<double>(kernel.QuadPart) +
|
||||
static_cast<double>(user.QuadPart)) *
|
||||
1e-7;
|
||||
}
|
||||
#elif !defined(BENCHMARK_OS_FUCHSIA)
|
||||
double MakeTime(struct rusage const& ru) {
|
||||
return (static_cast<double>(ru.ru_utime.tv_sec) +
|
||||
static_cast<double>(ru.ru_utime.tv_usec) * 1e-6 +
|
||||
static_cast<double>(ru.ru_stime.tv_sec) +
|
||||
static_cast<double>(ru.ru_stime.tv_usec) * 1e-6);
|
||||
}
|
||||
#endif
|
||||
#if defined(BENCHMARK_OS_MACOSX)
|
||||
double MakeTime(thread_basic_info_data_t const& info) {
|
||||
return (static_cast<double>(info.user_time.seconds) +
|
||||
static_cast<double>(info.user_time.microseconds) * 1e-6 +
|
||||
static_cast<double>(info.system_time.seconds) +
|
||||
static_cast<double>(info.system_time.microseconds) * 1e-6);
|
||||
}
|
||||
#endif
|
||||
#if defined(CLOCK_PROCESS_CPUTIME_ID) || defined(CLOCK_THREAD_CPUTIME_ID)
|
||||
double MakeTime(struct timespec const& ts) {
|
||||
return ts.tv_sec + (static_cast<double>(ts.tv_nsec) * 1e-9);
|
||||
}
|
||||
#endif
|
||||
|
||||
BENCHMARK_NORETURN static void DiagnoseAndExit(const char* msg) {
|
||||
std::cerr << "ERROR: " << msg << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
double ProcessCPUUsage() {
|
||||
#if defined(BENCHMARK_OS_WINDOWS)
|
||||
HANDLE proc = GetCurrentProcess();
|
||||
FILETIME creation_time;
|
||||
FILETIME exit_time;
|
||||
FILETIME kernel_time;
|
||||
FILETIME user_time;
|
||||
if (GetProcessTimes(proc, &creation_time, &exit_time, &kernel_time,
|
||||
&user_time))
|
||||
return MakeTime(kernel_time, user_time);
|
||||
DiagnoseAndExit("GetProccessTimes() failed");
|
||||
#elif defined(BENCHMARK_OS_EMSCRIPTEN)
|
||||
// clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) returns 0 on Emscripten.
|
||||
// Use Emscripten-specific API. Reported CPU time would be exactly the
|
||||
// same as total time, but this is ok because there aren't long-latency
|
||||
// syncronous system calls in Emscripten.
|
||||
return emscripten_get_now() * 1e-3;
|
||||
#elif defined(CLOCK_PROCESS_CPUTIME_ID) && !defined(BENCHMARK_OS_MACOSX)
|
||||
// FIXME We want to use clock_gettime, but its not available in MacOS 10.11. See
|
||||
// https://github.com/google/benchmark/pull/292
|
||||
struct timespec spec;
|
||||
if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &spec) == 0)
|
||||
return MakeTime(spec);
|
||||
DiagnoseAndExit("clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) failed");
|
||||
#else
|
||||
struct rusage ru;
|
||||
if (getrusage(RUSAGE_SELF, &ru) == 0) return MakeTime(ru);
|
||||
DiagnoseAndExit("getrusage(RUSAGE_SELF, ...) failed");
|
||||
#endif
|
||||
}
|
||||
|
||||
double ThreadCPUUsage() {
|
||||
#if defined(BENCHMARK_OS_WINDOWS)
|
||||
HANDLE this_thread = GetCurrentThread();
|
||||
FILETIME creation_time;
|
||||
FILETIME exit_time;
|
||||
FILETIME kernel_time;
|
||||
FILETIME user_time;
|
||||
GetThreadTimes(this_thread, &creation_time, &exit_time, &kernel_time,
|
||||
&user_time);
|
||||
return MakeTime(kernel_time, user_time);
|
||||
#elif defined(BENCHMARK_OS_MACOSX)
|
||||
// FIXME We want to use clock_gettime, but its not available in MacOS 10.11. See
|
||||
// https://github.com/google/benchmark/pull/292
|
||||
mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
|
||||
thread_basic_info_data_t info;
|
||||
mach_port_t thread = pthread_mach_thread_np(pthread_self());
|
||||
if (thread_info(thread, THREAD_BASIC_INFO, (thread_info_t)&info, &count) ==
|
||||
KERN_SUCCESS) {
|
||||
return MakeTime(info);
|
||||
}
|
||||
DiagnoseAndExit("ThreadCPUUsage() failed when evaluating thread_info");
|
||||
#elif defined(BENCHMARK_OS_EMSCRIPTEN)
|
||||
// Emscripten doesn't support traditional threads
|
||||
return ProcessCPUUsage();
|
||||
#elif defined(BENCHMARK_OS_RTEMS)
|
||||
// RTEMS doesn't support CLOCK_THREAD_CPUTIME_ID. See
|
||||
// https://github.com/RTEMS/rtems/blob/master/cpukit/posix/src/clockgettime.c
|
||||
return ProcessCPUUsage();
|
||||
#elif defined(BENCHMARK_OS_SOLARIS)
|
||||
struct rusage ru;
|
||||
if (getrusage(RUSAGE_LWP, &ru) == 0) return MakeTime(ru);
|
||||
DiagnoseAndExit("getrusage(RUSAGE_LWP, ...) failed");
|
||||
#elif defined(CLOCK_THREAD_CPUTIME_ID)
|
||||
struct timespec ts;
|
||||
if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) == 0) return MakeTime(ts);
|
||||
DiagnoseAndExit("clock_gettime(CLOCK_THREAD_CPUTIME_ID, ...) failed");
|
||||
#else
|
||||
#error Per-thread timing is not available on your system.
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
std::string DateTimeString(bool local) {
|
||||
typedef std::chrono::system_clock Clock;
|
||||
std::time_t now = Clock::to_time_t(Clock::now());
|
||||
const std::size_t kStorageSize = 128;
|
||||
char storage[kStorageSize];
|
||||
std::size_t written;
|
||||
|
||||
if (local) {
|
||||
#if defined(BENCHMARK_OS_WINDOWS)
|
||||
written =
|
||||
std::strftime(storage, sizeof(storage), "%x %X", ::localtime(&now));
|
||||
#else
|
||||
std::tm timeinfo;
|
||||
::localtime_r(&now, &timeinfo);
|
||||
written = std::strftime(storage, sizeof(storage), "%F %T", &timeinfo);
|
||||
#endif
|
||||
} else {
|
||||
#if defined(BENCHMARK_OS_WINDOWS)
|
||||
written = std::strftime(storage, sizeof(storage), "%x %X", ::gmtime(&now));
|
||||
#else
|
||||
std::tm timeinfo;
|
||||
::gmtime_r(&now, &timeinfo);
|
||||
written = std::strftime(storage, sizeof(storage), "%F %T", &timeinfo);
|
||||
#endif
|
||||
}
|
||||
CHECK(written < kStorageSize);
|
||||
((void)written); // prevent unused variable in optimized mode.
|
||||
return std::string(storage);
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
std::string LocalDateTimeString() { return DateTimeString(true); }
|
||||
|
||||
} // end namespace benchmark
|
||||
48
benchmarks/thirdparty/benchmark/src/timers.h
vendored
48
benchmarks/thirdparty/benchmark/src/timers.h
vendored
@@ -1,48 +0,0 @@
|
||||
#ifndef BENCHMARK_TIMERS_H
|
||||
#define BENCHMARK_TIMERS_H
|
||||
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
// Return the CPU usage of the current process
|
||||
double ProcessCPUUsage();
|
||||
|
||||
// Return the CPU usage of the children of the current process
|
||||
double ChildrenCPUUsage();
|
||||
|
||||
// Return the CPU usage of the current thread
|
||||
double ThreadCPUUsage();
|
||||
|
||||
#if defined(HAVE_STEADY_CLOCK)
|
||||
template <bool HighResIsSteady = std::chrono::high_resolution_clock::is_steady>
|
||||
struct ChooseSteadyClock {
|
||||
typedef std::chrono::high_resolution_clock type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ChooseSteadyClock<false> {
|
||||
typedef std::chrono::steady_clock type;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct ChooseClockType {
|
||||
#if defined(HAVE_STEADY_CLOCK)
|
||||
typedef ChooseSteadyClock<>::type type;
|
||||
#else
|
||||
typedef std::chrono::high_resolution_clock type;
|
||||
#endif
|
||||
};
|
||||
|
||||
inline double ChronoClockNow() {
|
||||
typedef ChooseClockType::type ClockType;
|
||||
using FpSeconds = std::chrono::duration<double, std::chrono::seconds::period>;
|
||||
return FpSeconds(ClockType::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
std::string LocalDateTimeString();
|
||||
|
||||
} // end namespace benchmark
|
||||
|
||||
#endif // BENCHMARK_TIMERS_H
|
||||
316
benchmarks/thirdparty/benchmark/tools/compare.py
vendored
316
benchmarks/thirdparty/benchmark/tools/compare.py
vendored
@@ -1,316 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
compare.py - versatile benchmark output compare tool
|
||||
"""
|
||||
|
||||
import argparse
|
||||
from argparse import ArgumentParser
|
||||
import sys
|
||||
import gbench
|
||||
from gbench import util, report
|
||||
from gbench.util import *
|
||||
|
||||
|
||||
def check_inputs(in1, in2, flags):
|
||||
"""
|
||||
Perform checking on the user provided inputs and diagnose any abnormalities
|
||||
"""
|
||||
in1_kind, in1_err = classify_input_file(in1)
|
||||
in2_kind, in2_err = classify_input_file(in2)
|
||||
output_file = find_benchmark_flag('--benchmark_out=', flags)
|
||||
output_type = find_benchmark_flag('--benchmark_out_format=', flags)
|
||||
if in1_kind == IT_Executable and in2_kind == IT_Executable and output_file:
|
||||
print(("WARNING: '--benchmark_out=%s' will be passed to both "
|
||||
"benchmarks causing it to be overwritten") % output_file)
|
||||
if in1_kind == IT_JSON and in2_kind == IT_JSON and len(flags) > 0:
|
||||
print("WARNING: passing optional flags has no effect since both "
|
||||
"inputs are JSON")
|
||||
if output_type is not None and output_type != 'json':
|
||||
print(("ERROR: passing '--benchmark_out_format=%s' to 'compare.py`"
|
||||
" is not supported.") % output_type)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def create_parser():
|
||||
parser = ArgumentParser(
|
||||
description='versatile benchmark output compare tool')
|
||||
subparsers = parser.add_subparsers(
|
||||
help='This tool has multiple modes of operation:',
|
||||
dest='mode')
|
||||
|
||||
parser_a = subparsers.add_parser(
|
||||
'benchmarks',
|
||||
help='The most simple use-case, compare all the output of these two benchmarks')
|
||||
baseline = parser_a.add_argument_group(
|
||||
'baseline', 'The benchmark baseline')
|
||||
baseline.add_argument(
|
||||
'test_baseline',
|
||||
metavar='test_baseline',
|
||||
type=argparse.FileType('r'),
|
||||
nargs=1,
|
||||
help='A benchmark executable or JSON output file')
|
||||
contender = parser_a.add_argument_group(
|
||||
'contender', 'The benchmark that will be compared against the baseline')
|
||||
contender.add_argument(
|
||||
'test_contender',
|
||||
metavar='test_contender',
|
||||
type=argparse.FileType('r'),
|
||||
nargs=1,
|
||||
help='A benchmark executable or JSON output file')
|
||||
parser_a.add_argument(
|
||||
'benchmark_options',
|
||||
metavar='benchmark_options',
|
||||
nargs=argparse.REMAINDER,
|
||||
help='Arguments to pass when running benchmark executables')
|
||||
|
||||
parser_b = subparsers.add_parser(
|
||||
'filters', help='Compare filter one with the filter two of benchmark')
|
||||
baseline = parser_b.add_argument_group(
|
||||
'baseline', 'The benchmark baseline')
|
||||
baseline.add_argument(
|
||||
'test',
|
||||
metavar='test',
|
||||
type=argparse.FileType('r'),
|
||||
nargs=1,
|
||||
help='A benchmark executable or JSON output file')
|
||||
baseline.add_argument(
|
||||
'filter_baseline',
|
||||
metavar='filter_baseline',
|
||||
type=str,
|
||||
nargs=1,
|
||||
help='The first filter, that will be used as baseline')
|
||||
contender = parser_b.add_argument_group(
|
||||
'contender', 'The benchmark that will be compared against the baseline')
|
||||
contender.add_argument(
|
||||
'filter_contender',
|
||||
metavar='filter_contender',
|
||||
type=str,
|
||||
nargs=1,
|
||||
help='The second filter, that will be compared against the baseline')
|
||||
parser_b.add_argument(
|
||||
'benchmark_options',
|
||||
metavar='benchmark_options',
|
||||
nargs=argparse.REMAINDER,
|
||||
help='Arguments to pass when running benchmark executables')
|
||||
|
||||
parser_c = subparsers.add_parser(
|
||||
'benchmarksfiltered',
|
||||
help='Compare filter one of first benchmark with filter two of the second benchmark')
|
||||
baseline = parser_c.add_argument_group(
|
||||
'baseline', 'The benchmark baseline')
|
||||
baseline.add_argument(
|
||||
'test_baseline',
|
||||
metavar='test_baseline',
|
||||
type=argparse.FileType('r'),
|
||||
nargs=1,
|
||||
help='A benchmark executable or JSON output file')
|
||||
baseline.add_argument(
|
||||
'filter_baseline',
|
||||
metavar='filter_baseline',
|
||||
type=str,
|
||||
nargs=1,
|
||||
help='The first filter, that will be used as baseline')
|
||||
contender = parser_c.add_argument_group(
|
||||
'contender', 'The benchmark that will be compared against the baseline')
|
||||
contender.add_argument(
|
||||
'test_contender',
|
||||
metavar='test_contender',
|
||||
type=argparse.FileType('r'),
|
||||
nargs=1,
|
||||
help='The second benchmark executable or JSON output file, that will be compared against the baseline')
|
||||
contender.add_argument(
|
||||
'filter_contender',
|
||||
metavar='filter_contender',
|
||||
type=str,
|
||||
nargs=1,
|
||||
help='The second filter, that will be compared against the baseline')
|
||||
parser_c.add_argument(
|
||||
'benchmark_options',
|
||||
metavar='benchmark_options',
|
||||
nargs=argparse.REMAINDER,
|
||||
help='Arguments to pass when running benchmark executables')
|
||||
|
||||
return parser
|
||||
|
||||
|
||||
def main():
|
||||
# Parse the command line flags
|
||||
parser = create_parser()
|
||||
args, unknown_args = parser.parse_known_args()
|
||||
if args.mode is None:
|
||||
parser.print_help()
|
||||
exit(1)
|
||||
assert not unknown_args
|
||||
benchmark_options = args.benchmark_options
|
||||
|
||||
if args.mode == 'benchmarks':
|
||||
test_baseline = args.test_baseline[0].name
|
||||
test_contender = args.test_contender[0].name
|
||||
filter_baseline = ''
|
||||
filter_contender = ''
|
||||
|
||||
# NOTE: if test_baseline == test_contender, you are analyzing the stdev
|
||||
|
||||
description = 'Comparing %s to %s' % (test_baseline, test_contender)
|
||||
elif args.mode == 'filters':
|
||||
test_baseline = args.test[0].name
|
||||
test_contender = args.test[0].name
|
||||
filter_baseline = args.filter_baseline[0]
|
||||
filter_contender = args.filter_contender[0]
|
||||
|
||||
# NOTE: if filter_baseline == filter_contender, you are analyzing the
|
||||
# stdev
|
||||
|
||||
description = 'Comparing %s to %s (from %s)' % (
|
||||
filter_baseline, filter_contender, args.test[0].name)
|
||||
elif args.mode == 'benchmarksfiltered':
|
||||
test_baseline = args.test_baseline[0].name
|
||||
test_contender = args.test_contender[0].name
|
||||
filter_baseline = args.filter_baseline[0]
|
||||
filter_contender = args.filter_contender[0]
|
||||
|
||||
# NOTE: if test_baseline == test_contender and
|
||||
# filter_baseline == filter_contender, you are analyzing the stdev
|
||||
|
||||
description = 'Comparing %s (from %s) to %s (from %s)' % (
|
||||
filter_baseline, test_baseline, filter_contender, test_contender)
|
||||
else:
|
||||
# should never happen
|
||||
print("Unrecognized mode of operation: '%s'" % args.mode)
|
||||
parser.print_help()
|
||||
exit(1)
|
||||
|
||||
check_inputs(test_baseline, test_contender, benchmark_options)
|
||||
|
||||
options_baseline = []
|
||||
options_contender = []
|
||||
|
||||
if filter_baseline and filter_contender:
|
||||
options_baseline = ['--benchmark_filter=%s' % filter_baseline]
|
||||
options_contender = ['--benchmark_filter=%s' % filter_contender]
|
||||
|
||||
# Run the benchmarks and report the results
|
||||
json1 = json1_orig = gbench.util.run_or_load_benchmark(
|
||||
test_baseline, benchmark_options + options_baseline)
|
||||
json2 = json2_orig = gbench.util.run_or_load_benchmark(
|
||||
test_contender, benchmark_options + options_contender)
|
||||
|
||||
# Now, filter the benchmarks so that the difference report can work
|
||||
if filter_baseline and filter_contender:
|
||||
replacement = '[%s vs. %s]' % (filter_baseline, filter_contender)
|
||||
json1 = gbench.report.filter_benchmark(
|
||||
json1_orig, filter_baseline, replacement)
|
||||
json2 = gbench.report.filter_benchmark(
|
||||
json2_orig, filter_contender, replacement)
|
||||
|
||||
# Diff and output
|
||||
output_lines = gbench.report.generate_difference_report(json1, json2)
|
||||
print(description)
|
||||
for ln in output_lines:
|
||||
print(ln)
|
||||
|
||||
|
||||
import unittest
|
||||
|
||||
|
||||
class TestParser(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.parser = create_parser()
|
||||
testInputs = os.path.join(
|
||||
os.path.dirname(
|
||||
os.path.realpath(__file__)),
|
||||
'gbench',
|
||||
'Inputs')
|
||||
self.testInput0 = os.path.join(testInputs, 'test1_run1.json')
|
||||
self.testInput1 = os.path.join(testInputs, 'test1_run2.json')
|
||||
|
||||
def test_benchmarks_basic(self):
|
||||
parsed = self.parser.parse_args(
|
||||
['benchmarks', self.testInput0, self.testInput1])
|
||||
self.assertEqual(parsed.mode, 'benchmarks')
|
||||
self.assertEqual(parsed.test_baseline[0].name, self.testInput0)
|
||||
self.assertEqual(parsed.test_contender[0].name, self.testInput1)
|
||||
self.assertFalse(parsed.benchmark_options)
|
||||
|
||||
def test_benchmarks_with_remainder(self):
|
||||
parsed = self.parser.parse_args(
|
||||
['benchmarks', self.testInput0, self.testInput1, 'd'])
|
||||
self.assertEqual(parsed.mode, 'benchmarks')
|
||||
self.assertEqual(parsed.test_baseline[0].name, self.testInput0)
|
||||
self.assertEqual(parsed.test_contender[0].name, self.testInput1)
|
||||
self.assertEqual(parsed.benchmark_options, ['d'])
|
||||
|
||||
def test_benchmarks_with_remainder_after_doubleminus(self):
|
||||
parsed = self.parser.parse_args(
|
||||
['benchmarks', self.testInput0, self.testInput1, '--', 'e'])
|
||||
self.assertEqual(parsed.mode, 'benchmarks')
|
||||
self.assertEqual(parsed.test_baseline[0].name, self.testInput0)
|
||||
self.assertEqual(parsed.test_contender[0].name, self.testInput1)
|
||||
self.assertEqual(parsed.benchmark_options, ['e'])
|
||||
|
||||
def test_filters_basic(self):
|
||||
parsed = self.parser.parse_args(
|
||||
['filters', self.testInput0, 'c', 'd'])
|
||||
self.assertEqual(parsed.mode, 'filters')
|
||||
self.assertEqual(parsed.test[0].name, self.testInput0)
|
||||
self.assertEqual(parsed.filter_baseline[0], 'c')
|
||||
self.assertEqual(parsed.filter_contender[0], 'd')
|
||||
self.assertFalse(parsed.benchmark_options)
|
||||
|
||||
def test_filters_with_remainder(self):
|
||||
parsed = self.parser.parse_args(
|
||||
['filters', self.testInput0, 'c', 'd', 'e'])
|
||||
self.assertEqual(parsed.mode, 'filters')
|
||||
self.assertEqual(parsed.test[0].name, self.testInput0)
|
||||
self.assertEqual(parsed.filter_baseline[0], 'c')
|
||||
self.assertEqual(parsed.filter_contender[0], 'd')
|
||||
self.assertEqual(parsed.benchmark_options, ['e'])
|
||||
|
||||
def test_filters_with_remainder_after_doubleminus(self):
|
||||
parsed = self.parser.parse_args(
|
||||
['filters', self.testInput0, 'c', 'd', '--', 'f'])
|
||||
self.assertEqual(parsed.mode, 'filters')
|
||||
self.assertEqual(parsed.test[0].name, self.testInput0)
|
||||
self.assertEqual(parsed.filter_baseline[0], 'c')
|
||||
self.assertEqual(parsed.filter_contender[0], 'd')
|
||||
self.assertEqual(parsed.benchmark_options, ['f'])
|
||||
|
||||
def test_benchmarksfiltered_basic(self):
|
||||
parsed = self.parser.parse_args(
|
||||
['benchmarksfiltered', self.testInput0, 'c', self.testInput1, 'e'])
|
||||
self.assertEqual(parsed.mode, 'benchmarksfiltered')
|
||||
self.assertEqual(parsed.test_baseline[0].name, self.testInput0)
|
||||
self.assertEqual(parsed.filter_baseline[0], 'c')
|
||||
self.assertEqual(parsed.test_contender[0].name, self.testInput1)
|
||||
self.assertEqual(parsed.filter_contender[0], 'e')
|
||||
self.assertFalse(parsed.benchmark_options)
|
||||
|
||||
def test_benchmarksfiltered_with_remainder(self):
|
||||
parsed = self.parser.parse_args(
|
||||
['benchmarksfiltered', self.testInput0, 'c', self.testInput1, 'e', 'f'])
|
||||
self.assertEqual(parsed.mode, 'benchmarksfiltered')
|
||||
self.assertEqual(parsed.test_baseline[0].name, self.testInput0)
|
||||
self.assertEqual(parsed.filter_baseline[0], 'c')
|
||||
self.assertEqual(parsed.test_contender[0].name, self.testInput1)
|
||||
self.assertEqual(parsed.filter_contender[0], 'e')
|
||||
self.assertEqual(parsed.benchmark_options[0], 'f')
|
||||
|
||||
def test_benchmarksfiltered_with_remainder_after_doubleminus(self):
|
||||
parsed = self.parser.parse_args(
|
||||
['benchmarksfiltered', self.testInput0, 'c', self.testInput1, 'e', '--', 'g'])
|
||||
self.assertEqual(parsed.mode, 'benchmarksfiltered')
|
||||
self.assertEqual(parsed.test_baseline[0].name, self.testInput0)
|
||||
self.assertEqual(parsed.filter_baseline[0], 'c')
|
||||
self.assertEqual(parsed.test_contender[0].name, self.testInput1)
|
||||
self.assertEqual(parsed.filter_contender[0], 'e')
|
||||
self.assertEqual(parsed.benchmark_options[0], 'g')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# unittest.main()
|
||||
main()
|
||||
|
||||
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
||||
# kate: tab-width: 4; replace-tabs on; indent-width 4; tab-indents: off;
|
||||
# kate: indent-mode python; remove-trailing-spaces modified;
|
||||
@@ -1,67 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
compare_bench.py - Compare two benchmarks or their results and report the
|
||||
difference.
|
||||
"""
|
||||
import argparse
|
||||
from argparse import ArgumentParser
|
||||
import sys
|
||||
import gbench
|
||||
from gbench import util, report
|
||||
from gbench.util import *
|
||||
|
||||
def check_inputs(in1, in2, flags):
|
||||
"""
|
||||
Perform checking on the user provided inputs and diagnose any abnormalities
|
||||
"""
|
||||
in1_kind, in1_err = classify_input_file(in1)
|
||||
in2_kind, in2_err = classify_input_file(in2)
|
||||
output_file = find_benchmark_flag('--benchmark_out=', flags)
|
||||
output_type = find_benchmark_flag('--benchmark_out_format=', flags)
|
||||
if in1_kind == IT_Executable and in2_kind == IT_Executable and output_file:
|
||||
print(("WARNING: '--benchmark_out=%s' will be passed to both "
|
||||
"benchmarks causing it to be overwritten") % output_file)
|
||||
if in1_kind == IT_JSON and in2_kind == IT_JSON and len(flags) > 0:
|
||||
print("WARNING: passing --benchmark flags has no effect since both "
|
||||
"inputs are JSON")
|
||||
if output_type is not None and output_type != 'json':
|
||||
print(("ERROR: passing '--benchmark_out_format=%s' to 'compare_bench.py`"
|
||||
" is not supported.") % output_type)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def main():
|
||||
parser = ArgumentParser(
|
||||
description='compare the results of two benchmarks')
|
||||
parser.add_argument(
|
||||
'test1', metavar='test1', type=str, nargs=1,
|
||||
help='A benchmark executable or JSON output file')
|
||||
parser.add_argument(
|
||||
'test2', metavar='test2', type=str, nargs=1,
|
||||
help='A benchmark executable or JSON output file')
|
||||
parser.add_argument(
|
||||
'benchmark_options', metavar='benchmark_options', nargs=argparse.REMAINDER,
|
||||
help='Arguments to pass when running benchmark executables'
|
||||
)
|
||||
args, unknown_args = parser.parse_known_args()
|
||||
# Parse the command line flags
|
||||
test1 = args.test1[0]
|
||||
test2 = args.test2[0]
|
||||
if unknown_args:
|
||||
# should never happen
|
||||
print("Unrecognized positional argument arguments: '%s'"
|
||||
% unknown_args)
|
||||
exit(1)
|
||||
benchmark_options = args.benchmark_options
|
||||
check_inputs(test1, test2, benchmark_options)
|
||||
# Run the benchmarks and report the results
|
||||
json1 = gbench.util.run_or_load_benchmark(test1, benchmark_options)
|
||||
json2 = gbench.util.run_or_load_benchmark(test2, benchmark_options)
|
||||
output_lines = gbench.report.generate_difference_report(json1, json2)
|
||||
print('Comparing %s to %s' % (test1, test2))
|
||||
for ln in output_lines:
|
||||
print(ln)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,102 +0,0 @@
|
||||
{
|
||||
"context": {
|
||||
"date": "2016-08-02 17:44:46",
|
||||
"num_cpus": 4,
|
||||
"mhz_per_cpu": 4228,
|
||||
"cpu_scaling_enabled": false,
|
||||
"library_build_type": "release"
|
||||
},
|
||||
"benchmarks": [
|
||||
{
|
||||
"name": "BM_SameTimes",
|
||||
"iterations": 1000,
|
||||
"real_time": 10,
|
||||
"cpu_time": 10,
|
||||
"time_unit": "ns"
|
||||
},
|
||||
{
|
||||
"name": "BM_2xFaster",
|
||||
"iterations": 1000,
|
||||
"real_time": 50,
|
||||
"cpu_time": 50,
|
||||
"time_unit": "ns"
|
||||
},
|
||||
{
|
||||
"name": "BM_2xSlower",
|
||||
"iterations": 1000,
|
||||
"real_time": 50,
|
||||
"cpu_time": 50,
|
||||
"time_unit": "ns"
|
||||
},
|
||||
{
|
||||
"name": "BM_1PercentFaster",
|
||||
"iterations": 1000,
|
||||
"real_time": 100,
|
||||
"cpu_time": 100,
|
||||
"time_unit": "ns"
|
||||
},
|
||||
{
|
||||
"name": "BM_1PercentSlower",
|
||||
"iterations": 1000,
|
||||
"real_time": 100,
|
||||
"cpu_time": 100,
|
||||
"time_unit": "ns"
|
||||
},
|
||||
{
|
||||
"name": "BM_10PercentFaster",
|
||||
"iterations": 1000,
|
||||
"real_time": 100,
|
||||
"cpu_time": 100,
|
||||
"time_unit": "ns"
|
||||
},
|
||||
{
|
||||
"name": "BM_10PercentSlower",
|
||||
"iterations": 1000,
|
||||
"real_time": 100,
|
||||
"cpu_time": 100,
|
||||
"time_unit": "ns"
|
||||
},
|
||||
{
|
||||
"name": "BM_100xSlower",
|
||||
"iterations": 1000,
|
||||
"real_time": 100,
|
||||
"cpu_time": 100,
|
||||
"time_unit": "ns"
|
||||
},
|
||||
{
|
||||
"name": "BM_100xFaster",
|
||||
"iterations": 1000,
|
||||
"real_time": 10000,
|
||||
"cpu_time": 10000,
|
||||
"time_unit": "ns"
|
||||
},
|
||||
{
|
||||
"name": "BM_10PercentCPUToTime",
|
||||
"iterations": 1000,
|
||||
"real_time": 100,
|
||||
"cpu_time": 100,
|
||||
"time_unit": "ns"
|
||||
},
|
||||
{
|
||||
"name": "BM_ThirdFaster",
|
||||
"iterations": 1000,
|
||||
"real_time": 100,
|
||||
"cpu_time": 100,
|
||||
"time_unit": "ns"
|
||||
},
|
||||
{
|
||||
"name": "BM_BadTimeUnit",
|
||||
"iterations": 1000,
|
||||
"real_time": 0.4,
|
||||
"cpu_time": 0.5,
|
||||
"time_unit": "s"
|
||||
},
|
||||
{
|
||||
"name": "BM_DifferentTimeUnit",
|
||||
"iterations": 1,
|
||||
"real_time": 1,
|
||||
"cpu_time": 1,
|
||||
"time_unit": "s"
|
||||
}
|
||||
]
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user