trunk/3rdparty/benchmark/LICENSE
| r0 | r253077 | |
| 1 | |
| 2 | Apache License |
| 3 | Version 2.0, January 2004 |
| 4 | http://www.apache.org/licenses/ |
| 5 | |
| 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION |
| 7 | |
| 8 | 1. Definitions. |
| 9 | |
| 10 | "License" shall mean the terms and conditions for use, reproduction, |
| 11 | and distribution as defined by Sections 1 through 9 of this document. |
| 12 | |
| 13 | "Licensor" shall mean the copyright owner or entity authorized by |
| 14 | the copyright owner that is granting the License. |
| 15 | |
| 16 | "Legal Entity" shall mean the union of the acting entity and all |
| 17 | other entities that control, are controlled by, or are under common |
| 18 | control with that entity. For the purposes of this definition, |
| 19 | "control" means (i) the power, direct or indirect, to cause the |
| 20 | direction or management of such entity, whether by contract or |
| 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the |
| 22 | outstanding shares, or (iii) beneficial ownership of such entity. |
| 23 | |
| 24 | "You" (or "Your") shall mean an individual or Legal Entity |
| 25 | exercising permissions granted by this License. |
| 26 | |
| 27 | "Source" form shall mean the preferred form for making modifications, |
| 28 | including but not limited to software source code, documentation |
| 29 | source, and configuration files. |
| 30 | |
| 31 | "Object" form shall mean any form resulting from mechanical |
| 32 | transformation or translation of a Source form, including but |
| 33 | not limited to compiled object code, generated documentation, |
| 34 | and conversions to other media types. |
| 35 | |
| 36 | "Work" shall mean the work of authorship, whether in Source or |
| 37 | Object form, made available under the License, as indicated by a |
| 38 | copyright notice that is included in or attached to the work |
| 39 | (an example is provided in the Appendix below). |
| 40 | |
| 41 | "Derivative Works" shall mean any work, whether in Source or Object |
| 42 | form, that is based on (or derived from) the Work and for which the |
| 43 | editorial revisions, annotations, elaborations, or other modifications |
| 44 | represent, as a whole, an original work of authorship. For the purposes |
| 45 | of this License, Derivative Works shall not include works that remain |
| 46 | separable from, or merely link (or bind by name) to the interfaces of, |
| 47 | the Work and Derivative Works thereof. |
| 48 | |
| 49 | "Contribution" shall mean any work of authorship, including |
| 50 | the original version of the Work and any modifications or additions |
| 51 | to that Work or Derivative Works thereof, that is intentionally |
| 52 | submitted to Licensor for inclusion in the Work by the copyright owner |
| 53 | or by an individual or Legal Entity authorized to submit on behalf of |
| 54 | the copyright owner. For the purposes of this definition, "submitted" |
| 55 | means any form of electronic, verbal, or written communication sent |
| 56 | to the Licensor or its representatives, including but not limited to |
| 57 | communication on electronic mailing lists, source code control systems, |
| 58 | and issue tracking systems that are managed by, or on behalf of, the |
| 59 | Licensor for the purpose of discussing and improving the Work, but |
| 60 | excluding communication that is conspicuously marked or otherwise |
| 61 | designated in writing by the copyright owner as "Not a Contribution." |
| 62 | |
| 63 | "Contributor" shall mean Licensor and any individual or Legal Entity |
| 64 | on behalf of whom a Contribution has been received by Licensor and |
| 65 | subsequently incorporated within the Work. |
| 66 | |
| 67 | 2. Grant of Copyright License. Subject to the terms and conditions of |
| 68 | this License, each Contributor hereby grants to You a perpetual, |
| 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
| 70 | copyright license to reproduce, prepare Derivative Works of, |
| 71 | publicly display, publicly perform, sublicense, and distribute the |
| 72 | Work and such Derivative Works in Source or Object form. |
| 73 | |
| 74 | 3. Grant of Patent License. Subject to the terms and conditions of |
| 75 | this License, each Contributor hereby grants to You a perpetual, |
| 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
| 77 | (except as stated in this section) patent license to make, have made, |
| 78 | use, offer to sell, sell, import, and otherwise transfer the Work, |
| 79 | where such license applies only to those patent claims licensable |
| 80 | by such Contributor that are necessarily infringed by their |
| 81 | Contribution(s) alone or by combination of their Contribution(s) |
| 82 | with the Work to which such Contribution(s) was submitted. If You |
| 83 | institute patent litigation against any entity (including a |
| 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work |
| 85 | or a Contribution incorporated within the Work constitutes direct |
| 86 | or contributory patent infringement, then any patent licenses |
| 87 | granted to You under this License for that Work shall terminate |
| 88 | as of the date such litigation is filed. |
| 89 | |
| 90 | 4. Redistribution. You may reproduce and distribute copies of the |
| 91 | Work or Derivative Works thereof in any medium, with or without |
| 92 | modifications, and in Source or Object form, provided that You |
| 93 | meet the following conditions: |
| 94 | |
| 95 | (a) You must give any other recipients of the Work or |
| 96 | Derivative Works a copy of this License; and |
| 97 | |
| 98 | (b) You must cause any modified files to carry prominent notices |
| 99 | stating that You changed the files; and |
| 100 | |
| 101 | (c) You must retain, in the Source form of any Derivative Works |
| 102 | that You distribute, all copyright, patent, trademark, and |
| 103 | attribution notices from the Source form of the Work, |
| 104 | excluding those notices that do not pertain to any part of |
| 105 | the Derivative Works; and |
| 106 | |
| 107 | (d) If the Work includes a "NOTICE" text file as part of its |
| 108 | distribution, then any Derivative Works that You distribute must |
| 109 | include a readable copy of the attribution notices contained |
| 110 | within such NOTICE file, excluding those notices that do not |
| 111 | pertain to any part of the Derivative Works, in at least one |
| 112 | of the following places: within a NOTICE text file distributed |
| 113 | as part of the Derivative Works; within the Source form or |
| 114 | documentation, if provided along with the Derivative Works; or, |
| 115 | within a display generated by the Derivative Works, if and |
| 116 | wherever such third-party notices normally appear. The contents |
| 117 | of the NOTICE file are for informational purposes only and |
| 118 | do not modify the License. You may add Your own attribution |
| 119 | notices within Derivative Works that You distribute, alongside |
| 120 | or as an addendum to the NOTICE text from the Work, provided |
| 121 | that such additional attribution notices cannot be construed |
| 122 | as modifying the License. |
| 123 | |
| 124 | You may add Your own copyright statement to Your modifications and |
| 125 | may provide additional or different license terms and conditions |
| 126 | for use, reproduction, or distribution of Your modifications, or |
| 127 | for any such Derivative Works as a whole, provided Your use, |
| 128 | reproduction, and distribution of the Work otherwise complies with |
| 129 | the conditions stated in this License. |
| 130 | |
| 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, |
| 132 | any Contribution intentionally submitted for inclusion in the Work |
| 133 | by You to the Licensor shall be under the terms and conditions of |
| 134 | this License, without any additional terms or conditions. |
| 135 | Notwithstanding the above, nothing herein shall supersede or modify |
| 136 | the terms of any separate license agreement you may have executed |
| 137 | with Licensor regarding such Contributions. |
| 138 | |
| 139 | 6. Trademarks. This License does not grant permission to use the trade |
| 140 | names, trademarks, service marks, or product names of the Licensor, |
| 141 | except as required for reasonable and customary use in describing the |
| 142 | origin of the Work and reproducing the content of the NOTICE file. |
| 143 | |
| 144 | 7. Disclaimer of Warranty. Unless required by applicable law or |
| 145 | agreed to in writing, Licensor provides the Work (and each |
| 146 | Contributor provides its Contributions) on an "AS IS" BASIS, |
| 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
| 148 | implied, including, without limitation, any warranties or conditions |
| 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A |
| 150 | PARTICULAR PURPOSE. You are solely responsible for determining the |
| 151 | appropriateness of using or redistributing the Work and assume any |
| 152 | risks associated with Your exercise of permissions under this License. |
| 153 | |
| 154 | 8. Limitation of Liability. In no event and under no legal theory, |
| 155 | whether in tort (including negligence), contract, or otherwise, |
| 156 | unless required by applicable law (such as deliberate and grossly |
| 157 | negligent acts) or agreed to in writing, shall any Contributor be |
| 158 | liable to You for damages, including any direct, indirect, special, |
| 159 | incidental, or consequential damages of any character arising as a |
| 160 | result of this License or out of the use or inability to use the |
| 161 | Work (including but not limited to damages for loss of goodwill, |
| 162 | work stoppage, computer failure or malfunction, or any and all |
| 163 | other commercial damages or losses), even if such Contributor |
| 164 | has been advised of the possibility of such damages. |
| 165 | |
| 166 | 9. Accepting Warranty or Additional Liability. While redistributing |
| 167 | the Work or Derivative Works thereof, You may choose to offer, |
| 168 | and charge a fee for, acceptance of support, warranty, indemnity, |
| 169 | or other liability obligations and/or rights consistent with this |
| 170 | License. However, in accepting such obligations, You may act only |
| 171 | on Your own behalf and on Your sole responsibility, not on behalf |
| 172 | of any other Contributor, and only if You agree to indemnify, |
| 173 | defend, and hold each Contributor harmless for any liability |
| 174 | incurred by, or claims asserted against, such Contributor by reason |
| 175 | of your accepting any such warranty or additional liability. |
| 176 | |
| 177 | END OF TERMS AND CONDITIONS |
| 178 | |
| 179 | APPENDIX: How to apply the Apache License to your work. |
| 180 | |
| 181 | To apply the Apache License to your work, attach the following |
| 182 | boilerplate notice, with the fields enclosed by brackets "[]" |
| 183 | replaced with your own identifying information. (Don't include |
| 184 | the brackets!) The text should be enclosed in the appropriate |
| 185 | comment syntax for the file format. We also recommend that a |
| 186 | file or class name and description of purpose be included on the |
| 187 | same "printed page" as the copyright notice for easier |
| 188 | identification within third-party archives. |
| 189 | |
| 190 | Copyright [yyyy] [name of copyright owner] |
| 191 | |
| 192 | Licensed under the Apache License, Version 2.0 (the "License"); |
| 193 | you may not use this file except in compliance with the License. |
| 194 | You may obtain a copy of the License at |
| 195 | |
| 196 | http://www.apache.org/licenses/LICENSE-2.0 |
| 197 | |
| 198 | Unless required by applicable law or agreed to in writing, software |
| 199 | distributed under the License is distributed on an "AS IS" BASIS, |
| 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 201 | See the License for the specific language governing permissions and |
| 202 | limitations under the License. |
trunk/3rdparty/benchmark/README.md
| r0 | r253077 | |
| 1 | benchmark |
| 2 | ========= |
| 3 | [](https://travis-ci.org/google/benchmark) |
| 4 | [](https://ci.appveyor.com/project/google/benchmark/branch/master) |
| 5 | [](https://coveralls.io/r/google/benchmark) |
| 6 | |
| 7 | A library to support the benchmarking of functions, similar to unit-tests. |
| 8 | |
| 9 | Discussion group: https://groups.google.com/d/forum/benchmark-discuss |
| 10 | |
| 11 | IRC channel: https://freenode.net #googlebenchmark |
| 12 | |
| 13 | Example usage |
| 14 | ------------- |
| 15 | Define a function that executes the code to be measured a |
| 16 | specified number of times: |
| 17 | |
| 18 | ```c++ |
| 19 | static void BM_StringCreation(benchmark::State& state) { |
| 20 | while (state.KeepRunning()) |
| 21 | std::string empty_string; |
| 22 | } |
| 23 | // Register the function as a benchmark |
| 24 | BENCHMARK(BM_StringCreation); |
| 25 | |
| 26 | // Define another benchmark |
| 27 | static void BM_StringCopy(benchmark::State& state) { |
| 28 | std::string x = "hello"; |
| 29 | while (state.KeepRunning()) |
| 30 | std::string copy(x); |
| 31 | } |
| 32 | BENCHMARK(BM_StringCopy); |
| 33 | |
| 34 | BENCHMARK_MAIN(); |
| 35 | ``` |
| 36 | |
| 37 | Sometimes a family of microbenchmarks can be implemented with |
| 38 | just one routine that takes an extra argument to specify which |
| 39 | one of the family of benchmarks to run. For example, the following |
| 40 | code defines a family of microbenchmarks for measuring the speed |
| 41 | of `memcpy()` calls of different lengths: |
| 42 | |
| 43 | ```c++ |
| 44 | static void BM_memcpy(benchmark::State& state) { |
| 45 | char* src = new char[state.range_x()]; char* dst = new char[state.range_x()]; |
| 46 | memset(src, 'x', state.range_x()); |
| 47 | while (state.KeepRunning()) |
| 48 | memcpy(dst, src, state.range_x()); |
| 49 | state.SetBytesProcessed(int64_t(state.iterations()) * |
| 50 | int64_t(state.range_x())); |
| 51 | delete[] src; |
| 52 | delete[] dst; |
| 53 | } |
| 54 | BENCHMARK(BM_memcpy)->Arg(8)->Arg(64)->Arg(512)->Arg(1<<10)->Arg(8<<10); |
| 55 | ``` |
| 56 | |
| 57 | The preceding code is quite repetitive, and can be replaced with the |
| 58 | following short-hand. The following invocation will pick a few |
| 59 | appropriate arguments in the specified range and will generate a |
| 60 | microbenchmark for each such argument. |
| 61 | |
| 62 | ```c++ |
| 63 | BENCHMARK(BM_memcpy)->Range(8, 8<<10); |
| 64 | ``` |
| 65 | |
| 66 | You might have a microbenchmark that depends on two inputs. For |
| 67 | example, the following code defines a family of microbenchmarks for |
| 68 | measuring the speed of set insertion. |
| 69 | |
| 70 | ```c++ |
| 71 | static void BM_SetInsert(benchmark::State& state) { |
| 72 | while (state.KeepRunning()) { |
| 73 | state.PauseTiming(); |
| 74 | std::set<int> data = ConstructRandomSet(state.range_x()); |
| 75 | state.ResumeTiming(); |
| 76 | for (int j = 0; j < state.range_y(); ++j) |
| 77 | data.insert(RandomNumber()); |
| 78 | } |
| 79 | } |
| 80 | BENCHMARK(BM_SetInsert) |
| 81 | ->ArgPair(1<<10, 1) |
| 82 | ->ArgPair(1<<10, 8) |
| 83 | ->ArgPair(1<<10, 64) |
| 84 | ->ArgPair(1<<10, 512) |
| 85 | ->ArgPair(8<<10, 1) |
| 86 | ->ArgPair(8<<10, 8) |
| 87 | ->ArgPair(8<<10, 64) |
| 88 | ->ArgPair(8<<10, 512); |
| 89 | ``` |
| 90 | |
| 91 | The preceding code is quite repetitive, and can be replaced with |
| 92 | the following short-hand. The following macro will pick a few |
| 93 | appropriate arguments in the product of the two specified ranges |
| 94 | and will generate a microbenchmark for each such pair. |
| 95 | |
| 96 | ```c++ |
| 97 | BENCHMARK(BM_SetInsert)->RangePair(1<<10, 8<<10, 1, 512); |
| 98 | ``` |
| 99 | |
| 100 | For more complex patterns of inputs, passing a custom function |
| 101 | to Apply allows programmatic specification of an |
| 102 | arbitrary set of arguments to run the microbenchmark on. |
| 103 | The following example enumerates a dense range on one parameter, |
| 104 | and a sparse range on the second. |
| 105 | |
| 106 | ```c++ |
| 107 | static void CustomArguments(benchmark::internal::Benchmark* b) { |
| 108 | for (int i = 0; i <= 10; ++i) |
| 109 | for (int j = 32; j <= 1024*1024; j *= 8) |
| 110 | b->ArgPair(i, j); |
| 111 | } |
| 112 | BENCHMARK(BM_SetInsert)->Apply(CustomArguments); |
| 113 | ``` |
| 114 | |
| 115 | Templated microbenchmarks work the same way: |
| 116 | Produce then consume 'size' messages 'iters' times |
| 117 | Measures throughput in the absence of multiprogramming. |
| 118 | |
| 119 | ```c++ |
| 120 | template <class Q> int BM_Sequential(benchmark::State& state) { |
| 121 | Q q; |
| 122 | typename Q::value_type v; |
| 123 | while (state.KeepRunning()) { |
| 124 | for (int i = state.range_x(); i--; ) |
| 125 | q.push(v); |
| 126 | for (int e = state.range_x(); e--; ) |
| 127 | q.Wait(&v); |
| 128 | } |
| 129 | // actually messages, not bytes: |
| 130 | state.SetBytesProcessed( |
| 131 | static_cast<int64_t>(state.iterations())*state.range_x()); |
| 132 | } |
| 133 | BENCHMARK_TEMPLATE(BM_Sequential, WaitQueue<int>)->Range(1<<0, 1<<10); |
| 134 | ``` |
| 135 | |
| 136 | Three macros are provided for adding benchmark templates. |
| 137 | |
| 138 | ```c++ |
| 139 | #if __cplusplus >= 201103L // C++11 and greater. |
| 140 | #define BENCHMARK_TEMPLATE(func, ...) // Takes any number of parameters. |
| 141 | #else // C++ < C++11 |
| 142 | #define BENCHMARK_TEMPLATE(func, arg1) |
| 143 | #endif |
| 144 | #define BENCHMARK_TEMPLATE1(func, arg1) |
| 145 | #define BENCHMARK_TEMPLATE2(func, arg1, arg2) |
| 146 | ``` |
| 147 | |
| 148 | In a multithreaded test (benchmark invoked by multiple threads simultaneously), |
| 149 | it is guaranteed that none of the threads will start until all have called |
| 150 | KeepRunning, and all will have finished before KeepRunning returns false. As |
| 151 | such, any global setup or teardown you want to do can be |
| 152 | wrapped in a check against the thread index: |
| 153 | |
| 154 | ```c++ |
| 155 | static void BM_MultiThreaded(benchmark::State& state) { |
| 156 | if (state.thread_index == 0) { |
| 157 | // Setup code here. |
| 158 | } |
| 159 | while (state.KeepRunning()) { |
| 160 | // Run the test as normal. |
| 161 | } |
| 162 | if (state.thread_index == 0) { |
| 163 | // Teardown code here. |
| 164 | } |
| 165 | } |
| 166 | BENCHMARK(BM_MultiThreaded)->Threads(2); |
| 167 | ``` |
| 168 | |
| 169 | If the benchmarked code itself uses threads and you want to compare it to |
| 170 | single-threaded code, you may want to use real-time ("wallclock") measurements |
| 171 | for latency comparisons: |
| 172 | |
| 173 | ```c++ |
| 174 | BENCHMARK(BM_test)->Range(8, 8<<10)->UseRealTime(); |
| 175 | ``` |
| 176 | |
| 177 | Without `UseRealTime`, CPU time is used by default. |
| 178 | |
| 179 | To prevent a value or expression from being optimized away by the compiler |
| 180 | the `benchmark::DoNotOptimize(...)` function can be used. |
| 181 | |
| 182 | ```c++ |
| 183 | static void BM_test(benchmark::State& state) { |
| 184 | while (state.KeepRunning()) { |
| 185 | int x = 0; |
| 186 | for (int i=0; i < 64; ++i) { |
| 187 | benchmark::DoNotOptimize(x += i); |
| 188 | } |
| 189 | } |
| 190 | } |
| 191 | ``` |
| 192 | |
| 193 | Benchmark Fixtures |
| 194 | ------------------ |
| 195 | Fixture tests are created by |
| 196 | first defining a type that derives from ::benchmark::Fixture and then |
| 197 | creating/registering the tests using the following macros: |
| 198 | |
| 199 | * `BENCHMARK_F(ClassName, Method)` |
| 200 | * `BENCHMARK_DEFINE_F(ClassName, Method)` |
| 201 | * `BENCHMARK_REGISTER_F(ClassName, Method)` |
| 202 | |
| 203 | For Example: |
| 204 | |
| 205 | ```c++ |
| 206 | class MyFixture : public benchmark::Fixture {}; |
| 207 | |
| 208 | BENCHMARK_F(MyFixture, FooTest)(benchmark::State& st) { |
| 209 | while (st.KeepRunning()) { |
| 210 | ... |
| 211 | } |
| 212 | } |
| 213 | |
| 214 | BENCHMARK_DEFINE_F(MyFixture, BarTest)(benchmark::State& st) { |
| 215 | while (st.KeepRunning()) { |
| 216 | ... |
| 217 | } |
| 218 | } |
| 219 | /* BarTest is NOT registered */ |
| 220 | BENCHMARK_REGISTER_F(MyFixture, BarTest)->Threads(2); |
| 221 | /* BarTest is now registered */ |
| 222 | ``` |
| 223 | |
| 224 | Output Formats |
| 225 | -------------- |
| 226 | The library supports multiple output formats. Use the |
| 227 | `--benchmark_format=<tabular|json>` flag to set the format type. `tabular` is |
| 228 | the default format. |
| 229 | |
| 230 | The Tabular format is intended to be a human readable format. By default |
| 231 | the format generates color output. Context is output on stderr and the |
| 232 | tabular data on stdout. Example tabular output looks like: |
| 233 | ``` |
| 234 | Benchmark Time(ns) CPU(ns) Iterations |
| 235 | ---------------------------------------------------------------------- |
| 236 | BM_SetInsert/1024/1 28928 29349 23853 133.097kB/s 33.2742k items/s |
| 237 | BM_SetInsert/1024/8 32065 32913 21375 949.487kB/s 237.372k items/s |
| 238 | BM_SetInsert/1024/10 33157 33648 21431 1.13369MB/s 290.225k items/s |
| 239 | ``` |
| 240 | |
| 241 | The JSON format outputs human readable json split into two top level attributes. |
| 242 | The `context` attribute contains information about the run in general, including |
| 243 | information about the CPU and the date. |
| 244 | The `benchmarks` attribute contains a list of ever benchmark run. Example json |
| 245 | output looks like: |
| 246 | ``` |
| 247 | { |
| 248 | "context": { |
| 249 | "date": "2015/03/17-18:40:25", |
| 250 | "num_cpus": 40, |
| 251 | "mhz_per_cpu": 2801, |
| 252 | "cpu_scaling_enabled": false, |
| 253 | "build_type": "debug" |
| 254 | }, |
| 255 | "benchmarks": [ |
| 256 | { |
| 257 | "name": "BM_SetInsert/1024/1", |
| 258 | "iterations": 94877, |
| 259 | "real_time": 29275, |
| 260 | "cpu_time": 29836, |
| 261 | "bytes_per_second": 134066, |
| 262 | "items_per_second": 33516 |
| 263 | }, |
| 264 | { |
| 265 | "name": "BM_SetInsert/1024/8", |
| 266 | "iterations": 21609, |
| 267 | "real_time": 32317, |
| 268 | "cpu_time": 32429, |
| 269 | "bytes_per_second": 986770, |
| 270 | "items_per_second": 246693 |
| 271 | }, |
| 272 | { |
| 273 | "name": "BM_SetInsert/1024/10", |
| 274 | "iterations": 21393, |
| 275 | "real_time": 32724, |
| 276 | "cpu_time": 33355, |
| 277 | "bytes_per_second": 1199226, |
| 278 | "items_per_second": 299807 |
| 279 | } |
| 280 | ] |
| 281 | } |
| 282 | ``` |
| 283 | |
| 284 | The CSV format outputs comma-separated values. The `context` is output on stderr |
| 285 | and the CSV itself on stdout. Example CSV output looks like: |
| 286 | ``` |
| 287 | name,iterations,real_time,cpu_time,bytes_per_second,items_per_second,label |
| 288 | "BM_SetInsert/1024/1",65465,17890.7,8407.45,475768,118942, |
| 289 | "BM_SetInsert/1024/8",116606,18810.1,9766.64,3.27646e+06,819115, |
| 290 | "BM_SetInsert/1024/10",106365,17238.4,8421.53,4.74973e+06,1.18743e+06, |
| 291 | ``` |
| 292 | |
| 293 | Linking against the library |
| 294 | --------------------------- |
| 295 | When using gcc, it is necessary to link against pthread to avoid runtime exceptions. This is due to how gcc implements std::thread. See [issue #67](https://github.com/google/benchmark/issues/67) for more details. |
trunk/3rdparty/benchmark/include/benchmark/benchmark_api.h
| r0 | r253077 | |
| 1 | // Support for registering benchmarks for functions. |
| 2 | |
| 3 | /* Example usage: |
| 4 | // Define a function that executes the code to be measured a |
| 5 | // specified number of times: |
| 6 | static void BM_StringCreation(benchmark::State& state) { |
| 7 | while (state.KeepRunning()) |
| 8 | std::string empty_string; |
| 9 | } |
| 10 | |
| 11 | // Register the function as a benchmark |
| 12 | BENCHMARK(BM_StringCreation); |
| 13 | |
| 14 | // Define another benchmark |
| 15 | static void BM_StringCopy(benchmark::State& state) { |
| 16 | std::string x = "hello"; |
| 17 | while (state.KeepRunning()) |
| 18 | std::string copy(x); |
| 19 | } |
| 20 | BENCHMARK(BM_StringCopy); |
| 21 | |
| 22 | // Augment the main() program to invoke benchmarks if specified |
| 23 | // via the --benchmarks command line flag. E.g., |
| 24 | // my_unittest --benchmark_filter=all |
| 25 | // my_unittest --benchmark_filter=BM_StringCreation |
| 26 | // my_unittest --benchmark_filter=String |
| 27 | // my_unittest --benchmark_filter='Copy|Creation' |
| 28 | int main(int argc, char** argv) { |
| 29 | benchmark::Initialize(&argc, argv); |
| 30 | benchmark::RunSpecifiedBenchmarks(); |
| 31 | return 0; |
| 32 | } |
| 33 | |
| 34 | // Sometimes a family of microbenchmarks can be implemented with |
| 35 | // just one routine that takes an extra argument to specify which |
| 36 | // one of the family of benchmarks to run. For example, the following |
| 37 | // code defines a family of microbenchmarks for measuring the speed |
| 38 | // of memcpy() calls of different lengths: |
| 39 | |
| 40 | static void BM_memcpy(benchmark::State& state) { |
| 41 | char* src = new char[state.range_x()]; char* dst = new char[state.range_x()]; |
| 42 | memset(src, 'x', state.range_x()); |
| 43 | while (state.KeepRunning()) |
| 44 | memcpy(dst, src, state.range_x()); |
| 45 | state.SetBytesProcessed(int64_t(state.iterations()) * |
| 46 | int64_t(state.range_x())); |
| 47 | delete[] src; delete[] dst; |
| 48 | } |
| 49 | BENCHMARK(BM_memcpy)->Arg(8)->Arg(64)->Arg(512)->Arg(1<<10)->Arg(8<<10); |
| 50 | |
| 51 | // The preceding code is quite repetitive, and can be replaced with the |
| 52 | // following short-hand. The following invocation will pick a few |
| 53 | // appropriate arguments in the specified range and will generate a |
| 54 | // microbenchmark for each such argument. |
| 55 | BENCHMARK(BM_memcpy)->Range(8, 8<<10); |
| 56 | |
| 57 | // You might have a microbenchmark that depends on two inputs. For |
| 58 | // example, the following code defines a family of microbenchmarks for |
| 59 | // measuring the speed of set insertion. |
| 60 | static void BM_SetInsert(benchmark::State& state) { |
| 61 | while (state.KeepRunning()) { |
| 62 | state.PauseTiming(); |
| 63 | set<int> data = ConstructRandomSet(state.range_x()); |
| 64 | state.ResumeTiming(); |
| 65 | for (int j = 0; j < state.range_y(); ++j) |
| 66 | data.insert(RandomNumber()); |
| 67 | } |
| 68 | } |
| 69 | BENCHMARK(BM_SetInsert) |
| 70 | ->ArgPair(1<<10, 1) |
| 71 | ->ArgPair(1<<10, 8) |
| 72 | ->ArgPair(1<<10, 64) |
| 73 | ->ArgPair(1<<10, 512) |
| 74 | ->ArgPair(8<<10, 1) |
| 75 | ->ArgPair(8<<10, 8) |
| 76 | ->ArgPair(8<<10, 64) |
| 77 | ->ArgPair(8<<10, 512); |
| 78 | |
| 79 | // The preceding code is quite repetitive, and can be replaced with |
| 80 | // the following short-hand. The following macro will pick a few |
| 81 | // appropriate arguments in the product of the two specified ranges |
| 82 | // and will generate a microbenchmark for each such pair. |
| 83 | BENCHMARK(BM_SetInsert)->RangePair(1<<10, 8<<10, 1, 512); |
| 84 | |
| 85 | // For more complex patterns of inputs, passing a custom function |
| 86 | // to Apply allows programmatic specification of an |
| 87 | // arbitrary set of arguments to run the microbenchmark on. |
| 88 | // The following example enumerates a dense range on |
| 89 | // one parameter, and a sparse range on the second. |
| 90 | static void CustomArguments(benchmark::internal::Benchmark* b) { |
| 91 | for (int i = 0; i <= 10; ++i) |
| 92 | for (int j = 32; j <= 1024*1024; j *= 8) |
| 93 | b->ArgPair(i, j); |
| 94 | } |
| 95 | BENCHMARK(BM_SetInsert)->Apply(CustomArguments); |
| 96 | |
| 97 | // Templated microbenchmarks work the same way: |
| 98 | // Produce then consume 'size' messages 'iters' times |
| 99 | // Measures throughput in the absence of multiprogramming. |
| 100 | template <class Q> int BM_Sequential(benchmark::State& state) { |
| 101 | Q q; |
| 102 | typename Q::value_type v; |
| 103 | while (state.KeepRunning()) { |
| 104 | for (int i = state.range_x(); i--; ) |
| 105 | q.push(v); |
| 106 | for (int e = state.range_x(); e--; ) |
| 107 | q.Wait(&v); |
| 108 | } |
| 109 | // actually messages, not bytes: |
| 110 | state.SetBytesProcessed( |
| 111 | static_cast<int64_t>(state.iterations())*state.range_x()); |
| 112 | } |
| 113 | BENCHMARK_TEMPLATE(BM_Sequential, WaitQueue<int>)->Range(1<<0, 1<<10); |
| 114 | |
| 115 | Use `Benchmark::MinTime(double t)` to set the minimum time used to run the |
| 116 | benchmark. This option overrides the `benchmark_min_time` flag. |
| 117 | |
| 118 | void BM_test(benchmark::State& state) { |
| 119 | ... body ... |
| 120 | } |
| 121 | BENCHMARK(BM_test)->MinTime(2.0); // Run for at least 2 seconds. |
| 122 | |
| 123 | In a multithreaded test, it is guaranteed that none of the threads will start |
| 124 | until all have called KeepRunning, and all will have finished before KeepRunning |
| 125 | returns false. As such, any global setup or teardown you want to do can be |
| 126 | wrapped in a check against the thread index: |
| 127 | |
| 128 | static void BM_MultiThreaded(benchmark::State& state) { |
| 129 | if (state.thread_index == 0) { |
| 130 | // Setup code here. |
| 131 | } |
| 132 | while (state.KeepRunning()) { |
| 133 | // Run the test as normal. |
| 134 | } |
| 135 | if (state.thread_index == 0) { |
| 136 | // Teardown code here. |
| 137 | } |
| 138 | } |
| 139 | BENCHMARK(BM_MultiThreaded)->Threads(4); |
| 140 | */ |
| 141 | |
| 142 | #ifndef BENCHMARK_BENCHMARK_API_H_ |
| 143 | #define BENCHMARK_BENCHMARK_API_H_ |
| 144 | |
| 145 | #include <assert.h> |
| 146 | #include <stddef.h> |
| 147 | #include <stdint.h> |
| 148 | |
| 149 | #include "macros.h" |
| 150 | |
| 151 | namespace benchmark { |
| 152 | class BenchmarkReporter; |
| 153 | |
| 154 | void Initialize(int* argc, char** argv); |
| 155 | |
| 156 | // Otherwise, run all benchmarks specified by the --benchmark_filter flag, |
| 157 | // and exit after running the benchmarks. |
| 158 | void RunSpecifiedBenchmarks(); |
| 159 | void RunSpecifiedBenchmarks(BenchmarkReporter* reporter); |
| 160 | |
| 161 | // If this routine is called, peak memory allocation past this point in the |
| 162 | // benchmark is reported at the end of the benchmark report line. (It is |
| 163 | // computed by running the benchmark once with a single iteration and a memory |
| 164 | // tracer.) |
| 165 | // TODO(dominic) |
| 166 | // void MemoryUsage(); |
| 167 | |
| 168 | namespace internal { |
| 169 | class Benchmark; |
| 170 | class BenchmarkImp; |
| 171 | class BenchmarkFamilies; |
| 172 | |
| 173 | template <class T> struct Voider { |
| 174 | typedef void type; |
| 175 | }; |
| 176 | |
| 177 | template <class T, class = void> |
| 178 | struct EnableIfString {}; |
| 179 | |
| 180 | template <class T> |
| 181 | struct EnableIfString<T, typename Voider<typename T::basic_string>::type> { |
| 182 | typedef int type; |
| 183 | }; |
| 184 | |
| 185 | void UseCharPointer(char const volatile*); |
| 186 | |
| 187 | // Take ownership of the pointer and register the benchmark. Return the |
| 188 | // registered benchmark. |
| 189 | Benchmark* RegisterBenchmarkInternal(Benchmark*); |
| 190 | |
| 191 | } // end namespace internal |
| 192 | |
| 193 | |
| 194 | // The DoNotOptimize(...) function can be used to prevent a value or |
| 195 | // expression from being optimized away by the compiler. This function is |
| 196 | // intented to add little to no overhead. |
| 197 | // See: http://stackoverflow.com/questions/28287064 |
| 198 | #if defined(__clang__) && defined(__GNUC__) |
| 199 | // TODO(ericwf): Clang has a bug where it tries to always use a register |
| 200 | // even if value must be stored in memory. This causes codegen to fail. |
| 201 | // To work around this we remove the "r" modifier so the operand is always |
| 202 | // loaded into memory. |
| 203 | template <class Tp> |
| 204 | inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { |
| 205 | asm volatile("" : "+m" (const_cast<Tp&>(value))); |
| 206 | } |
| 207 | #elif defined(__GNUC__) |
| 208 | template <class Tp> |
| 209 | inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { |
| 210 | asm volatile("" : "+rm" (const_cast<Tp&>(value))); |
| 211 | } |
| 212 | #else |
| 213 | template <class Tp> |
| 214 | inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { |
| 215 | internal::UseCharPointer(&reinterpret_cast<char const volatile&>(value)); |
| 216 | } |
| 217 | #endif |
| 218 | |
| 219 | |
| 220 | // State is passed to a running Benchmark and contains state for the |
| 221 | // benchmark to use. |
| 222 | class State { |
| 223 | public: |
| 224 | State(size_t max_iters, bool has_x, int x, bool has_y, int y, int thread_i); |
| 225 | |
| 226 | // Returns true iff the benchmark should continue through another iteration. |
| 227 | // NOTE: A benchmark may not return from the test until KeepRunning() has |
| 228 | // returned false. |
| 229 | bool KeepRunning() { |
| 230 | if (BENCHMARK_BUILTIN_EXPECT(!started_, false)) { |
| 231 | ResumeTiming(); |
| 232 | started_ = true; |
| 233 | } |
| 234 | bool const res = total_iterations_++ < max_iterations; |
| 235 | if (BENCHMARK_BUILTIN_EXPECT(!res, false)) { |
| 236 | assert(started_); |
| 237 | PauseTiming(); |
| 238 | // Total iterations now is one greater than max iterations. Fix this. |
| 239 | total_iterations_ = max_iterations; |
| 240 | } |
| 241 | return res; |
| 242 | } |
| 243 | |
| 244 | // REQUIRES: timer is running |
| 245 | // Stop the benchmark timer. If not called, the timer will be |
| 246 | // automatically stopped after KeepRunning() returns false for the first time. |
| 247 | // |
| 248 | // For threaded benchmarks the PauseTiming() function acts |
| 249 | // like a barrier. I.e., the ith call by a particular thread to this |
| 250 | // function will block until all threads have made their ith call. |
| 251 | // The timer will stop when the last thread has called this function. |
| 252 | // |
| 253 | // NOTE: PauseTiming()/ResumeTiming() are relatively |
| 254 | // heavyweight, and so their use should generally be avoided |
| 255 | // within each benchmark iteration, if possible. |
| 256 | void PauseTiming(); |
| 257 | |
| 258 | // REQUIRES: timer is not running |
| 259 | // Start the benchmark timer. The timer is NOT running on entrance to the |
| 260 | // benchmark function. It begins running after the first call to KeepRunning() |
| 261 | // |
| 262 | // For threaded benchmarks the ResumeTiming() function acts |
| 263 | // like a barrier. I.e., the ith call by a particular thread to this |
| 264 | // function will block until all threads have made their ith call. |
| 265 | // The timer will start when the last thread has called this function. |
| 266 | // |
| 267 | // NOTE: PauseTiming()/ResumeTiming() are relatively |
| 268 | // heavyweight, and so their use should generally be avoided |
| 269 | // within each benchmark iteration, if possible. |
| 270 | void ResumeTiming(); |
| 271 | |
| 272 | // Set the number of bytes processed by the current benchmark |
| 273 | // execution. This routine is typically called once at the end of a |
| 274 | // throughput oriented benchmark. If this routine is called with a |
| 275 | // value > 0, the report is printed in MB/sec instead of nanoseconds |
| 276 | // per iteration. |
| 277 | // |
| 278 | // REQUIRES: a benchmark has exited its KeepRunning loop. |
| 279 | BENCHMARK_ALWAYS_INLINE |
| 280 | void SetBytesProcessed(size_t bytes) { |
| 281 | bytes_processed_ = bytes; |
| 282 | } |
| 283 | |
| 284 | BENCHMARK_ALWAYS_INLINE |
| 285 | size_t bytes_processed() const { |
| 286 | return bytes_processed_; |
| 287 | } |
| 288 | |
| 289 | // If this routine is called with items > 0, then an items/s |
| 290 | // label is printed on the benchmark report line for the currently |
| 291 | // executing benchmark. It is typically called at the end of a processing |
| 292 | // benchmark where a processing items/second output is desired. |
| 293 | // |
| 294 | // REQUIRES: a benchmark has exited its KeepRunning loop. |
| 295 | BENCHMARK_ALWAYS_INLINE |
| 296 | void SetItemsProcessed(size_t items) { |
| 297 | items_processed_ = items; |
| 298 | } |
| 299 | |
| 300 | BENCHMARK_ALWAYS_INLINE |
| 301 | size_t items_processed() const { |
| 302 | return items_processed_; |
| 303 | } |
| 304 | |
| 305 | // If this routine is called, the specified label is printed at the |
| 306 | // end of the benchmark report line for the currently executing |
| 307 | // benchmark. Example: |
| 308 | // static void BM_Compress(int iters) { |
| 309 | // ... |
| 310 | // double compress = input_size / output_size; |
| 311 | // benchmark::SetLabel(StringPrintf("compress:%.1f%%", 100.0*compression)); |
| 312 | // } |
| 313 | // Produces output that looks like: |
| 314 | // BM_Compress 50 50 14115038 compress:27.3% |
| 315 | // |
| 316 | // REQUIRES: a benchmark has exited its KeepRunning loop. |
| 317 | void SetLabel(const char* label); |
| 318 | |
| 319 | // Allow the use of std::string without actually including <string>. |
| 320 | // This function does not participate in overload resolution unless StringType |
| 321 | // has the nested typename `basic_string`. This typename should be provided |
| 322 | // as an injected class name in the case of std::string. |
| 323 | template <class StringType> |
| 324 | void SetLabel(StringType const & str, |
| 325 | typename internal::EnableIfString<StringType>::type = 1) { |
| 326 | this->SetLabel(str.c_str()); |
| 327 | } |
| 328 | |
| 329 | // Range arguments for this run. CHECKs if the argument has been set. |
| 330 | BENCHMARK_ALWAYS_INLINE |
| 331 | int range_x() const { |
| 332 | assert(has_range_x_); |
| 333 | ((void)has_range_x_); // Prevent unused warning. |
| 334 | return range_x_; |
| 335 | } |
| 336 | |
| 337 | BENCHMARK_ALWAYS_INLINE |
| 338 | int range_y() const { |
| 339 | assert(has_range_y_); |
| 340 | ((void)has_range_y_); // Prevent unused warning. |
| 341 | return range_y_; |
| 342 | } |
| 343 | |
| 344 | BENCHMARK_ALWAYS_INLINE |
| 345 | size_t iterations() const { return total_iterations_; } |
| 346 | |
| 347 | private: |
| 348 | bool started_; |
| 349 | size_t total_iterations_; |
| 350 | |
| 351 | bool has_range_x_; |
| 352 | int range_x_; |
| 353 | |
| 354 | bool has_range_y_; |
| 355 | int range_y_; |
| 356 | |
| 357 | size_t bytes_processed_; |
| 358 | size_t items_processed_; |
| 359 | |
| 360 | public: |
| 361 | const int thread_index; |
| 362 | const size_t max_iterations; |
| 363 | |
| 364 | private: |
| 365 | BENCHMARK_DISALLOW_COPY_AND_ASSIGN(State); |
| 366 | }; |
| 367 | |
| 368 | namespace internal { |
| 369 | |
| 370 | typedef void(Function)(State&); |
| 371 | |
| 372 | // ------------------------------------------------------ |
| 373 | // Benchmark registration object. The BENCHMARK() macro expands |
| 374 | // into an internal::Benchmark* object. Various methods can |
| 375 | // be called on this object to change the properties of the benchmark. |
| 376 | // Each method returns "this" so that multiple method calls can |
| 377 | // chained into one expression. |
| 378 | class Benchmark { |
| 379 | public: |
| 380 | virtual ~Benchmark(); |
| 381 | |
| 382 | // Note: the following methods all return "this" so that multiple |
| 383 | // method calls can be chained together in one expression. |
| 384 | |
| 385 | // Run this benchmark once with "x" as the extra argument passed |
| 386 | // to the function. |
| 387 | // REQUIRES: The function passed to the constructor must accept an arg1. |
| 388 | Benchmark* Arg(int x); |
| 389 | |
| 390 | // Run this benchmark once for a number of values picked from the |
| 391 | // range [start..limit]. (start and limit are always picked.) |
| 392 | // REQUIRES: The function passed to the constructor must accept an arg1. |
| 393 | Benchmark* Range(int start, int limit); |
| 394 | |
| 395 | // Run this benchmark once for every value in the range [start..limit] |
| 396 | // REQUIRES: The function passed to the constructor must accept an arg1. |
| 397 | Benchmark* DenseRange(int start, int limit); |
| 398 | |
| 399 | // Run this benchmark once with "x,y" as the extra arguments passed |
| 400 | // to the function. |
| 401 | // REQUIRES: The function passed to the constructor must accept arg1,arg2. |
| 402 | Benchmark* ArgPair(int x, int y); |
| 403 | |
| 404 | // Pick a set of values A from the range [lo1..hi1] and a set |
| 405 | // of values B from the range [lo2..hi2]. Run the benchmark for |
| 406 | // every pair of values in the cartesian product of A and B |
| 407 | // (i.e., for all combinations of the values in A and B). |
| 408 | // REQUIRES: The function passed to the constructor must accept arg1,arg2. |
| 409 | Benchmark* RangePair(int lo1, int hi1, int lo2, int hi2); |
| 410 | |
| 411 | // Pass this benchmark object to *func, which can customize |
| 412 | // the benchmark by calling various methods like Arg, ArgPair, |
| 413 | // Threads, etc. |
| 414 | Benchmark* Apply(void (*func)(Benchmark* benchmark)); |
| 415 | |
| 416 | // Set the minimum amount of time to use when running this benchmark. This |
| 417 | // option overrides the `benchmark_min_time` flag. |
| 418 | Benchmark* MinTime(double t); |
| 419 | |
| 420 | // If a particular benchmark is I/O bound, runs multiple threads internally or |
| 421 | // if for some reason CPU timings are not representative, call this method. If |
| 422 | // called, the elapsed time will be used to control how many iterations are |
| 423 | // run, and in the printing of items/second or MB/seconds values. If not |
| 424 | // called, the cpu time used by the benchmark will be used. |
| 425 | Benchmark* UseRealTime(); |
| 426 | |
| 427 | // Support for running multiple copies of the same benchmark concurrently |
| 428 | // in multiple threads. This may be useful when measuring the scaling |
| 429 | // of some piece of code. |
| 430 | |
| 431 | // Run one instance of this benchmark concurrently in t threads. |
| 432 | Benchmark* Threads(int t); |
| 433 | |
| 434 | // Pick a set of values T from [min_threads,max_threads]. |
| 435 | // min_threads and max_threads are always included in T. Run this |
| 436 | // benchmark once for each value in T. The benchmark run for a |
| 437 | // particular value t consists of t threads running the benchmark |
| 438 | // function concurrently. For example, consider: |
| 439 | // BENCHMARK(Foo)->ThreadRange(1,16); |
| 440 | // This will run the following benchmarks: |
| 441 | // Foo in 1 thread |
| 442 | // Foo in 2 threads |
| 443 | // Foo in 4 threads |
| 444 | // Foo in 8 threads |
| 445 | // Foo in 16 threads |
| 446 | Benchmark* ThreadRange(int min_threads, int max_threads); |
| 447 | |
| 448 | // Equivalent to ThreadRange(NumCPUs(), NumCPUs()) |
| 449 | Benchmark* ThreadPerCpu(); |
| 450 | |
| 451 | virtual void Run(State& state) = 0; |
| 452 | |
| 453 | // Used inside the benchmark implementation |
| 454 | struct Instance; |
| 455 | |
| 456 | protected: |
| 457 | explicit Benchmark(const char* name); |
| 458 | Benchmark(Benchmark const&); |
| 459 | void SetName(const char* name); |
| 460 | |
| 461 | private: |
| 462 | friend class BenchmarkFamilies; |
| 463 | BenchmarkImp* imp_; |
| 464 | |
| 465 | Benchmark& operator=(Benchmark const&); |
| 466 | }; |
| 467 | |
| 468 | // The class used to hold all Benchmarks created from static function. |
| 469 | // (ie those created using the BENCHMARK(...) macros. |
| 470 | class FunctionBenchmark : public Benchmark { |
| 471 | public: |
| 472 | FunctionBenchmark(const char* name, Function* func) |
| 473 | : Benchmark(name), func_(func) |
| 474 | {} |
| 475 | |
| 476 | virtual void Run(State& st); |
| 477 | private: |
| 478 | Function* func_; |
| 479 | }; |
| 480 | |
| 481 | } // end namespace internal |
| 482 | |
| 483 | // The base class for all fixture tests. |
| 484 | class Fixture: public internal::Benchmark { |
| 485 | public: |
| 486 | Fixture() : internal::Benchmark("") {} |
| 487 | |
| 488 | virtual void Run(State& st) { |
| 489 | this->SetUp(); |
| 490 | this->BenchmarkCase(st); |
| 491 | this->TearDown(); |
| 492 | } |
| 493 | |
| 494 | virtual void SetUp() {} |
| 495 | virtual void TearDown() {} |
| 496 | |
| 497 | protected: |
| 498 | virtual void BenchmarkCase(State&) = 0; |
| 499 | }; |
| 500 | |
| 501 | } // end namespace benchmark |
| 502 | |
| 503 | |
| 504 | // ------------------------------------------------------ |
| 505 | // Macro to register benchmarks |
| 506 | |
| 507 | // Check that __COUNTER__ is defined and that __COUNTER__ increases by 1 |
| 508 | // every time it is expanded. X + 1 == X + 0 is used in case X is defined to be |
| 509 | // empty. If X is empty the expression becomes (+1 == +0). |
| 510 | #if defined(__COUNTER__) && (__COUNTER__ + 1 == __COUNTER__ + 0) |
| 511 | #define BENCHMARK_PRIVATE_UNIQUE_ID __COUNTER__ |
| 512 | #else |
| 513 | #define BENCHMARK_PRIVATE_UNIQUE_ID __LINE__ |
| 514 | #endif |
| 515 | |
| 516 | // Helpers for generating unique variable names |
| 517 | #define BENCHMARK_PRIVATE_NAME(n) \ |
| 518 | BENCHMARK_PRIVATE_CONCAT(_benchmark_, BENCHMARK_PRIVATE_UNIQUE_ID, n) |
| 519 | #define BENCHMARK_PRIVATE_CONCAT(a, b, c) BENCHMARK_PRIVATE_CONCAT2(a, b, c) |
| 520 | #define BENCHMARK_PRIVATE_CONCAT2(a, b, c) a##b##c |
| 521 | |
| 522 | #define BENCHMARK_PRIVATE_DECLARE(n) \ |
| 523 | static ::benchmark::internal::Benchmark* \ |
| 524 | BENCHMARK_PRIVATE_NAME(n) BENCHMARK_UNUSED |
| 525 | |
| 526 | #define BENCHMARK(n) \ |
| 527 | BENCHMARK_PRIVATE_DECLARE(n) = \ |
| 528 | (::benchmark::internal::RegisterBenchmarkInternal( \ |
| 529 | new ::benchmark::internal::FunctionBenchmark(#n, n))) |
| 530 | |
| 531 | // Old-style macros |
| 532 | #define BENCHMARK_WITH_ARG(n, a) BENCHMARK(n)->Arg((a)) |
| 533 | #define BENCHMARK_WITH_ARG2(n, a1, a2) BENCHMARK(n)->ArgPair((a1), (a2)) |
| 534 | #define BENCHMARK_RANGE(n, lo, hi) BENCHMARK(n)->Range((lo), (hi)) |
| 535 | #define BENCHMARK_RANGE2(n, l1, h1, l2, h2) \ |
| 536 | BENCHMARK(n)->RangePair((l1), (h1), (l2), (h2)) |
| 537 | |
| 538 | // This will register a benchmark for a templatized function. For example: |
| 539 | // |
| 540 | // template<int arg> |
| 541 | // void BM_Foo(int iters); |
| 542 | // |
| 543 | // BENCHMARK_TEMPLATE(BM_Foo, 1); |
| 544 | // |
| 545 | // will register BM_Foo<1> as a benchmark. |
| 546 | #define BENCHMARK_TEMPLATE1(n, a) \ |
| 547 | BENCHMARK_PRIVATE_DECLARE(n) = \ |
| 548 | (::benchmark::internal::RegisterBenchmarkInternal( \ |
| 549 | new ::benchmark::internal::FunctionBenchmark(#n "<" #a ">", n<a>))) |
| 550 | |
| 551 | #define BENCHMARK_TEMPLATE2(n, a, b) \ |
| 552 | BENCHMARK_PRIVATE_DECLARE(n) = \ |
| 553 | (::benchmark::internal::RegisterBenchmarkInternal( \ |
| 554 | new ::benchmark::internal::FunctionBenchmark( \ |
| 555 | #n "<" #a "," #b ">", n<a, b>))) |
| 556 | |
| 557 | #if __cplusplus >= 201103L |
| 558 | #define BENCHMARK_TEMPLATE(n, ...) \ |
| 559 | BENCHMARK_PRIVATE_DECLARE(n) = \ |
| 560 | (::benchmark::internal::RegisterBenchmarkInternal( \ |
| 561 | new ::benchmark::internal::FunctionBenchmark( \ |
| 562 | #n "<" #__VA_ARGS__ ">", n<__VA_ARGS__>))) |
| 563 | #else |
| 564 | #define BENCHMARK_TEMPLATE(n, a) BENCHMARK_TEMPLATE1(n, a) |
| 565 | #endif |
| 566 | |
| 567 | |
| 568 | #define BENCHMARK_PRIVATE_DECLARE_F(BaseClass, Method) \ |
| 569 | class BaseClass##_##Method##_Benchmark : public BaseClass { \ |
| 570 | public: \ |
| 571 | BaseClass##_##Method##_Benchmark() : BaseClass() { \ |
| 572 | this->SetName(#BaseClass "/" #Method);} \ |
| 573 | protected: \ |
| 574 | virtual void BenchmarkCase(::benchmark::State&); \ |
| 575 | }; |
| 576 | |
| 577 | #define BENCHMARK_DEFINE_F(BaseClass, Method) \ |
| 578 | BENCHMARK_PRIVATE_DECLARE_F(BaseClass, Method) \ |
| 579 | void BaseClass##_##Method##_Benchmark::BenchmarkCase |
| 580 | |
| 581 | #define BENCHMARK_REGISTER_F(BaseClass, Method) \ |
| 582 | BENCHMARK_PRIVATE_REGISTER_F(BaseClass##_##Method##_Benchmark) |
| 583 | |
| 584 | #define BENCHMARK_PRIVATE_REGISTER_F(TestName) \ |
| 585 | BENCHMARK_PRIVATE_DECLARE(TestName) = \ |
| 586 | (::benchmark::internal::RegisterBenchmarkInternal(new TestName())) |
| 587 | |
| 588 | // This macro will define and register a benchmark within a fixture class. |
| 589 | #define BENCHMARK_F(BaseClass, Method) \ |
| 590 | BENCHMARK_PRIVATE_DECLARE_F(BaseClass, Method) \ |
| 591 | BENCHMARK_REGISTER_F(BaseClass, Method); \ |
| 592 | void BaseClass##_##Method##_Benchmark::BenchmarkCase |
| 593 | |
| 594 | |
| 595 | // Helper macro to create a main routine in a test that runs the benchmarks |
| 596 | #define BENCHMARK_MAIN() \ |
| 597 | int main(int argc, char** argv) { \ |
| 598 | ::benchmark::Initialize(&argc, argv); \ |
| 599 | ::benchmark::RunSpecifiedBenchmarks(); \ |
| 600 | } |
| 601 | |
| 602 | #endif // BENCHMARK_BENCHMARK_API_H_ |
trunk/3rdparty/benchmark/mingw.py
| r0 | r253077 | |
| 1 | #! /usr/bin/env python |
| 2 | # encoding: utf-8 |
| 3 | |
| 4 | import argparse |
| 5 | import errno |
| 6 | import logging |
| 7 | import os |
| 8 | import platform |
| 9 | import re |
| 10 | import sys |
| 11 | import subprocess |
| 12 | import tempfile |
| 13 | |
| 14 | try: |
| 15 | import winreg |
| 16 | except ImportError: |
| 17 | import _winreg as winreg |
| 18 | try: |
| 19 | import urllib.request as request |
| 20 | except ImportError: |
| 21 | import urllib as request |
| 22 | try: |
| 23 | import urllib.parse as parse |
| 24 | except ImportError: |
| 25 | import urlparse as parse |
| 26 | |
| 27 | class EmptyLogger(object): |
| 28 | ''' |
| 29 | Provides an implementation that performs no logging |
| 30 | ''' |
| 31 | def debug(self, *k, **kw): |
| 32 | pass |
| 33 | def info(self, *k, **kw): |
| 34 | pass |
| 35 | def warn(self, *k, **kw): |
| 36 | pass |
| 37 | def error(self, *k, **kw): |
| 38 | pass |
| 39 | def critical(self, *k, **kw): |
| 40 | pass |
| 41 | def setLevel(self, *k, **kw): |
| 42 | pass |
| 43 | |
| 44 | urls = ( |
| 45 | 'http://downloads.sourceforge.net/project/mingw-w64/Toolchains%20' |
| 46 | 'targetting%20Win32/Personal%20Builds/mingw-builds/installer/' |
| 47 | 'repository.txt', |
| 48 | 'http://downloads.sourceforge.net/project/mingwbuilds/host-windows/' |
| 49 | 'repository.txt' |
| 50 | ) |
| 51 | ''' |
| 52 | A list of mingw-build repositories |
| 53 | ''' |
| 54 | |
| 55 | def repository(urls = urls, log = EmptyLogger()): |
| 56 | ''' |
| 57 | Downloads and parse mingw-build repository files and parses them |
| 58 | ''' |
| 59 | log.info('getting mingw-builds repository') |
| 60 | versions = {} |
| 61 | re_sourceforge = re.compile(r'http://sourceforge.net/projects/([^/]+)/files') |
| 62 | re_sub = r'http://downloads.sourceforge.net/project/\1' |
| 63 | for url in urls: |
| 64 | log.debug(' - requesting: %s', url) |
| 65 | socket = request.urlopen(url) |
| 66 | repo = socket.read() |
| 67 | if not isinstance(repo, str): |
| 68 | repo = repo.decode(); |
| 69 | socket.close() |
| 70 | for entry in repo.split('\n')[:-1]: |
| 71 | value = entry.split('|') |
| 72 | version = tuple([int(n) for n in value[0].strip().split('.')]) |
| 73 | version = versions.setdefault(version, {}) |
| 74 | arch = value[1].strip() |
| 75 | if arch == 'x32': |
| 76 | arch = 'i686' |
| 77 | elif arch == 'x64': |
| 78 | arch = 'x86_64' |
| 79 | arch = version.setdefault(arch, {}) |
| 80 | threading = arch.setdefault(value[2].strip(), {}) |
| 81 | exceptions = threading.setdefault(value[3].strip(), {}) |
| 82 | revision = exceptions.setdefault(int(value[4].strip()[3:]), |
| 83 | re_sourceforge.sub(re_sub, value[5].strip())) |
| 84 | return versions |
| 85 | |
| 86 | def find_in_path(file, path=None): |
| 87 | ''' |
| 88 | Attempts to find an executable in the path |
| 89 | ''' |
| 90 | if platform.system() == 'Windows': |
| 91 | file += '.exe' |
| 92 | if path is None: |
| 93 | path = os.environ.get('PATH', '') |
| 94 | if type(path) is type(''): |
| 95 | path = path.split(os.pathsep) |
| 96 | return list(filter(os.path.exists, |
| 97 | map(lambda dir, file=file: os.path.join(dir, file), path))) |
| 98 | |
| 99 | def find_7zip(log = EmptyLogger()): |
| 100 | ''' |
| 101 | Attempts to find 7zip for unpacking the mingw-build archives |
| 102 | ''' |
| 103 | log.info('finding 7zip') |
| 104 | path = find_in_path('7z') |
| 105 | if not path: |
| 106 | key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r'SOFTWARE\7-Zip') |
| 107 | path, _ = winreg.QueryValueEx(key, 'Path') |
| 108 | path = [os.path.join(path, '7z.exe')] |
| 109 | log.debug('found \'%s\'', path[0]) |
| 110 | return path[0] |
| 111 | |
| 112 | find_7zip() |
| 113 | |
| 114 | def unpack(archive, location, log = EmptyLogger()): |
| 115 | ''' |
| 116 | Unpacks a mingw-builds archive |
| 117 | ''' |
| 118 | sevenzip = find_7zip(log) |
| 119 | log.info('unpacking %s', os.path.basename(archive)) |
| 120 | cmd = [sevenzip, 'x', archive, '-o' + location, '-y'] |
| 121 | log.debug(' - %r', cmd) |
| 122 | with open(os.devnull, 'w') as devnull: |
| 123 | subprocess.check_call(cmd, stdout = devnull) |
| 124 | |
| 125 | def download(url, location, log = EmptyLogger()): |
| 126 | ''' |
| 127 | Downloads and unpacks a mingw-builds archive |
| 128 | ''' |
| 129 | log.info('downloading MinGW') |
| 130 | log.debug(' - url: %s', url) |
| 131 | log.debug(' - location: %s', location) |
| 132 | |
| 133 | re_content = re.compile(r'attachment;[ \t]*filename=(")?([^"]*)(")?[\r\n]*') |
| 134 | |
| 135 | stream = request.urlopen(url) |
| 136 | try: |
| 137 | content = stream.getheader('Content-Disposition') or '' |
| 138 | except AttributeError: |
| 139 | content = stream.headers.getheader('Content-Disposition') or '' |
| 140 | matches = re_content.match(content) |
| 141 | if matches: |
| 142 | filename = matches.group(2) |
| 143 | else: |
| 144 | parsed = parse.urlparse(stream.geturl()) |
| 145 | filename = os.path.basename(parsed.path) |
| 146 | |
| 147 | try: |
| 148 | os.makedirs(location) |
| 149 | except OSError as e: |
| 150 | if e.errno == errno.EEXIST and os.path.isdir(location): |
| 151 | pass |
| 152 | else: |
| 153 | raise |
| 154 | |
| 155 | archive = os.path.join(location, filename) |
| 156 | with open(archive, 'wb') as out: |
| 157 | while True: |
| 158 | buf = stream.read(1024) |
| 159 | if not buf: |
| 160 | break |
| 161 | out.write(buf) |
| 162 | unpack(archive, location, log = log) |
| 163 | os.remove(archive) |
| 164 | |
| 165 | possible = os.path.join(location, 'mingw64') |
| 166 | if not os.path.exists(possible): |
| 167 | possible = os.path.join(location, 'mingw32') |
| 168 | if not os.path.exists(possible): |
| 169 | raise ValueError('Failed to find unpacked MinGW: ' + possible) |
| 170 | return possible |
| 171 | |
| 172 | def root(location = None, arch = None, version = None, threading = None, |
| 173 | exceptions = None, revision = None, log = EmptyLogger()): |
| 174 | ''' |
| 175 | Returns the root folder of a specific version of the mingw-builds variant |
| 176 | of gcc. Will download the compiler if needed |
| 177 | ''' |
| 178 | |
| 179 | # Get the repository if we don't have all the information |
| 180 | if not (arch and version and threading and exceptions and revision): |
| 181 | versions = repository(log = log) |
| 182 | |
| 183 | # Determine some defaults |
| 184 | version = version or max(versions.keys()) |
| 185 | if not arch: |
| 186 | arch = platform.machine().lower() |
| 187 | if arch == 'x86': |
| 188 | arch = 'i686' |
| 189 | elif arch == 'amd64': |
| 190 | arch = 'x86_64' |
| 191 | if not threading: |
| 192 | keys = versions[version][arch].keys() |
| 193 | if 'posix' in keys: |
| 194 | threading = 'posix' |
| 195 | elif 'win32' in keys: |
| 196 | threading = 'win32' |
| 197 | else: |
| 198 | threading = keys[0] |
| 199 | if not exceptions: |
| 200 | keys = versions[version][arch][threading].keys() |
| 201 | if 'seh' in keys: |
| 202 | exceptions = 'seh' |
| 203 | elif 'sjlj' in keys: |
| 204 | exceptions = 'sjlj' |
| 205 | else: |
| 206 | exceptions = keys[0] |
| 207 | if revision == None: |
| 208 | revision = max(versions[version][arch][threading][exceptions].keys()) |
| 209 | if not location: |
| 210 | location = os.path.join(tempfile.gettempdir(), 'mingw-builds') |
| 211 | |
| 212 | # Get the download url |
| 213 | url = versions[version][arch][threading][exceptions][revision] |
| 214 | |
| 215 | # Tell the user whatzzup |
| 216 | log.info('finding MinGW %s', '.'.join(str(v) for v in version)) |
| 217 | log.debug(' - arch: %s', arch) |
| 218 | log.debug(' - threading: %s', threading) |
| 219 | log.debug(' - exceptions: %s', exceptions) |
| 220 | log.debug(' - revision: %s', revision) |
| 221 | log.debug(' - url: %s', url) |
| 222 | |
| 223 | # Store each specific revision differently |
| 224 | slug = '{version}-{arch}-{threading}-{exceptions}-rev{revision}' |
| 225 | slug = slug.format( |
| 226 | version = '.'.join(str(v) for v in version), |
| 227 | arch = arch, |
| 228 | threading = threading, |
| 229 | exceptions = exceptions, |
| 230 | revision = revision |
| 231 | ) |
| 232 | if arch == 'x86_64': |
| 233 | root_dir = os.path.join(location, slug, 'mingw64') |
| 234 | elif arch == 'i686': |
| 235 | root_dir = os.path.join(location, slug, 'mingw32') |
| 236 | else: |
| 237 | raise ValueError('Unknown MinGW arch: ' + arch) |
| 238 | |
| 239 | # Download if needed |
| 240 | if not os.path.exists(root_dir): |
| 241 | downloaded = download(url, os.path.join(location, slug), log = log) |
| 242 | if downloaded != root_dir: |
| 243 | raise ValueError('The location of mingw did not match\n%s\n%s' |
| 244 | % (downloaded, root_dir)) |
| 245 | |
| 246 | return root_dir |
| 247 | |
| 248 | def str2ver(string): |
| 249 | ''' |
| 250 | Converts a version string into a tuple |
| 251 | ''' |
| 252 | try: |
| 253 | version = tuple(int(v) for v in string.split('.')) |
| 254 | if len(version) is not 3: |
| 255 | raise ValueError() |
| 256 | except ValueError: |
| 257 | raise argparse.ArgumentTypeError( |
| 258 | 'please provide a three digit version string') |
| 259 | return version |
| 260 | |
| 261 | def main(): |
| 262 | ''' |
| 263 | Invoked when the script is run directly by the python interpreter |
| 264 | ''' |
| 265 | parser = argparse.ArgumentParser( |
| 266 | description = 'Downloads a specific version of MinGW', |
| 267 | formatter_class = argparse.ArgumentDefaultsHelpFormatter |
| 268 | ) |
| 269 | parser.add_argument('--location', |
| 270 | help = 'the location to download the compiler to', |
| 271 | default = os.path.join(tempfile.gettempdir(), 'mingw-builds')) |
| 272 | parser.add_argument('--arch', required = True, choices = ['i686', 'x86_64'], |
| 273 | help = 'the target MinGW architecture string') |
| 274 | parser.add_argument('--version', type = str2ver, |
| 275 | help = 'the version of GCC to download') |
| 276 | parser.add_argument('--threading', choices = ['posix', 'win32'], |
| 277 | help = 'the threading type of the compiler') |
| 278 | parser.add_argument('--exceptions', choices = ['sjlj', 'seh', 'dwarf'], |
| 279 | help = 'the method to throw exceptions') |
| 280 | parser.add_argument('--revision', type=int, |
| 281 | help = 'the revision of the MinGW release') |
| 282 | group = parser.add_mutually_exclusive_group() |
| 283 | group.add_argument('-v', '--verbose', action='store_true', |
| 284 | help='increase the script output verbosity') |
| 285 | group.add_argument('-q', '--quiet', action='store_true', |
| 286 | help='only print errors and warning') |
| 287 | args = parser.parse_args() |
| 288 | |
| 289 | # Create the logger |
| 290 | logger = logging.getLogger('mingw') |
| 291 | handler = logging.StreamHandler() |
| 292 | formatter = logging.Formatter('%(message)s') |
| 293 | handler.setFormatter(formatter) |
| 294 | logger.addHandler(handler) |
| 295 | logger.setLevel(logging.INFO) |
| 296 | if args.quiet: |
| 297 | logger.setLevel(logging.WARN) |
| 298 | if args.verbose: |
| 299 | logger.setLevel(logging.DEBUG) |
| 300 | |
| 301 | # Get MinGW |
| 302 | root_dir = root(location = args.location, arch = args.arch, |
| 303 | version = args.version, threading = args.threading, |
| 304 | exceptions = args.exceptions, revision = args.revision, |
| 305 | log = logger) |
| 306 | |
| 307 | sys.stdout.write('%s\n' % os.path.join(root_dir, 'bin')) |
| 308 | |
| 309 | if __name__ == '__main__': |
| 310 | try: |
| 311 | main() |
| 312 | except IOError as e: |
| 313 | sys.stderr.write('IO error: %s\n' % e) |
| 314 | sys.exit(1) |
| 315 | except OSError as e: |
| 316 | sys.stderr.write('OS error: %s\n' % e) |
| 317 | sys.exit(1) |
| 318 | except KeyboardInterrupt as e: |
| 319 | sys.stderr.write('Killed\n') |
| 320 | sys.exit(1) |
trunk/3rdparty/benchmark/src/benchmark.cc
| r0 | r253077 | |
| 1 | // Copyright 2015 Google Inc. All rights reserved. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | #include "benchmark/benchmark.h" |
| 16 | #include "internal_macros.h" |
| 17 | |
| 18 | #ifndef BENCHMARK_OS_WINDOWS |
| 19 | #include <sys/time.h> |
| 20 | #include <sys/resource.h> |
| 21 | #include <unistd.h> |
| 22 | #endif |
| 23 | |
| 24 | #include <cstdlib> |
| 25 | #include <cstring> |
| 26 | #include <cstdio> |
| 27 | #include <algorithm> |
| 28 | #include <atomic> |
| 29 | #include <condition_variable> |
| 30 | #include <iostream> |
| 31 | #include <memory> |
| 32 | #include <thread> |
| 33 | |
| 34 | #include "check.h" |
| 35 | #include "commandlineflags.h" |
| 36 | #include "log.h" |
| 37 | #include "mutex.h" |
| 38 | #include "re.h" |
| 39 | #include "stat.h" |
| 40 | #include "string_util.h" |
| 41 | #include "sysinfo.h" |
| 42 | #include "walltime.h" |
| 43 | |
| 44 | DEFINE_bool(benchmark_list_tests, false, |
| 45 | "Print a list of benchmarks. This option overrides all other " |
| 46 | "options."); |
| 47 | |
| 48 | DEFINE_string(benchmark_filter, ".", |
| 49 | "A regular expression that specifies the set of benchmarks " |
| 50 | "to execute. If this flag is empty, no benchmarks are run. " |
| 51 | "If this flag is the string \"all\", all benchmarks linked " |
| 52 | "into the process are run."); |
| 53 | |
| 54 | DEFINE_double(benchmark_min_time, 0.5, |
| 55 | "Minimum number of seconds we should run benchmark before " |
| 56 | "results are considered significant. For cpu-time based " |
| 57 | "tests, this is the lower bound on the total cpu time " |
| 58 | "used by all threads that make up the test. For real-time " |
| 59 | "based tests, this is the lower bound on the elapsed time " |
| 60 | "of the benchmark execution, regardless of number of " |
| 61 | "threads."); |
| 62 | |
| 63 | DEFINE_int32(benchmark_repetitions, 1, |
| 64 | "The number of runs of each benchmark. If greater than 1, the " |
| 65 | "mean and standard deviation of the runs will be reported."); |
| 66 | |
| 67 | DEFINE_string(benchmark_format, "tabular", |
| 68 | "The format to use for console output. Valid values are " |
| 69 | "'tabular', 'json', or 'csv'."); |
| 70 | |
| 71 | DEFINE_bool(color_print, true, "Enables colorized logging."); |
| 72 | |
| 73 | DEFINE_int32(v, 0, "The level of verbose logging to output"); |
| 74 | |
| 75 | |
| 76 | namespace benchmark { |
| 77 | |
| 78 | namespace internal { |
| 79 | |
| 80 | void UseCharPointer(char const volatile*) {} |
| 81 | |
| 82 | // NOTE: This is a dummy "mutex" type used to denote the actual mutex |
| 83 | // returned by GetBenchmarkLock(). This is only used to placate the thread |
| 84 | // safety warnings by giving the return of GetBenchmarkLock() a name. |
| 85 | struct CAPABILITY("mutex") BenchmarkLockType {}; |
| 86 | BenchmarkLockType BenchmarkLockVar; |
| 87 | |
| 88 | } // end namespace internal |
| 89 | |
| 90 | inline Mutex& RETURN_CAPABILITY(::benchmark::internal::BenchmarkLockVar) |
| 91 | GetBenchmarkLock() |
| 92 | { |
| 93 | static Mutex lock; |
| 94 | return lock; |
| 95 | } |
| 96 | |
| 97 | namespace { |
| 98 | |
| 99 | bool IsZero(double n) { |
| 100 | return std::abs(n) < std::numeric_limits<double>::epsilon(); |
| 101 | } |
| 102 | |
| 103 | // For non-dense Range, intermediate values are powers of kRangeMultiplier. |
| 104 | static const int kRangeMultiplier = 8; |
| 105 | static const size_t kMaxIterations = 1000000000; |
| 106 | |
| 107 | bool running_benchmark = false; |
| 108 | |
| 109 | // Global variable so that a benchmark can cause a little extra printing |
| 110 | std::string* GetReportLabel() { |
| 111 | static std::string label GUARDED_BY(GetBenchmarkLock()); |
| 112 | return &label; |
| 113 | } |
| 114 | |
| 115 | // TODO(ericwf): support MallocCounter. |
| 116 | //static benchmark::MallocCounter *benchmark_mc; |
| 117 | |
| 118 | struct ThreadStats { |
| 119 | ThreadStats() : bytes_processed(0), items_processed(0) {} |
| 120 | int64_t bytes_processed; |
| 121 | int64_t items_processed; |
| 122 | }; |
| 123 | |
| 124 | // Timer management class |
| 125 | class TimerManager { |
| 126 | public: |
| 127 | TimerManager(int num_threads, Notification* done) |
| 128 | : num_threads_(num_threads), |
| 129 | done_(done), |
| 130 | running_(false), |
| 131 | real_time_used_(0), |
| 132 | cpu_time_used_(0), |
| 133 | num_finalized_(0), |
| 134 | phase_number_(0), |
| 135 | entered_(0) { |
| 136 | } |
| 137 | |
| 138 | // Called by each thread |
| 139 | void StartTimer() EXCLUDES(lock_) { |
| 140 | bool last_thread = false; |
| 141 | { |
| 142 | MutexLock ml(lock_); |
| 143 | last_thread = Barrier(ml); |
| 144 | if (last_thread) { |
| 145 | CHECK(!running_) << "Called StartTimer when timer is already running"; |
| 146 | running_ = true; |
| 147 | start_real_time_ = walltime::Now(); |
| 148 | start_cpu_time_ = MyCPUUsage() + ChildrenCPUUsage(); |
| 149 | } |
| 150 | } |
| 151 | if (last_thread) { |
| 152 | phase_condition_.notify_all(); |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | // Called by each thread |
| 157 | void StopTimer() EXCLUDES(lock_) { |
| 158 | bool last_thread = false; |
| 159 | { |
| 160 | MutexLock ml(lock_); |
| 161 | last_thread = Barrier(ml); |
| 162 | if (last_thread) { |
| 163 | CHECK(running_) << "Called StopTimer when timer is already stopped"; |
| 164 | InternalStop(); |
| 165 | } |
| 166 | } |
| 167 | if (last_thread) { |
| 168 | phase_condition_.notify_all(); |
| 169 | } |
| 170 | } |
| 171 | |
| 172 | // Called by each thread |
| 173 | void Finalize() EXCLUDES(lock_) { |
| 174 | MutexLock l(lock_); |
| 175 | num_finalized_++; |
| 176 | if (num_finalized_ == num_threads_) { |
| 177 | CHECK(!running_) << |
| 178 | "The timer should be stopped before the timer is finalized"; |
| 179 | done_->Notify(); |
| 180 | } |
| 181 | } |
| 182 | |
| 183 | // REQUIRES: timer is not running |
| 184 | double real_time_used() EXCLUDES(lock_) { |
| 185 | MutexLock l(lock_); |
| 186 | CHECK(!running_); |
| 187 | return real_time_used_; |
| 188 | } |
| 189 | |
| 190 | // REQUIRES: timer is not running |
| 191 | double cpu_time_used() EXCLUDES(lock_) { |
| 192 | MutexLock l(lock_); |
| 193 | CHECK(!running_); |
| 194 | return cpu_time_used_; |
| 195 | } |
| 196 | |
| 197 | private: |
| 198 | Mutex lock_; |
| 199 | Condition phase_condition_; |
| 200 | int num_threads_; |
| 201 | Notification* done_; |
| 202 | |
| 203 | bool running_; // Is the timer running |
| 204 | double start_real_time_; // If running_ |
| 205 | double start_cpu_time_; // If running_ |
| 206 | |
| 207 | // Accumulated time so far (does not contain current slice if running_) |
| 208 | double real_time_used_; |
| 209 | double cpu_time_used_; |
| 210 | |
| 211 | // How many threads have called Finalize() |
| 212 | int num_finalized_; |
| 213 | |
| 214 | // State for barrier management |
| 215 | int phase_number_; |
| 216 | int entered_; // Number of threads that have entered this barrier |
| 217 | |
| 218 | void InternalStop() REQUIRES(lock_) { |
| 219 | CHECK(running_); |
| 220 | running_ = false; |
| 221 | real_time_used_ += walltime::Now() - start_real_time_; |
| 222 | cpu_time_used_ += ((MyCPUUsage() + ChildrenCPUUsage()) |
| 223 | - start_cpu_time_); |
| 224 | } |
| 225 | |
| 226 | // Enter the barrier and wait until all other threads have also |
| 227 | // entered the barrier. Returns iff this is the last thread to |
| 228 | // enter the barrier. |
| 229 | bool Barrier(MutexLock& ml) REQUIRES(lock_) { |
| 230 | CHECK_LT(entered_, num_threads_); |
| 231 | entered_++; |
| 232 | if (entered_ < num_threads_) { |
| 233 | // Wait for all threads to enter |
| 234 | int phase_number_cp = phase_number_; |
| 235 | auto cb = [this, phase_number_cp]() { |
| 236 | return this->phase_number_ > phase_number_cp; |
| 237 | }; |
| 238 | phase_condition_.wait(ml.native_handle(), cb); |
| 239 | return false; // I was not the last one |
| 240 | } else { |
| 241 | // Last thread has reached the barrier |
| 242 | phase_number_++; |
| 243 | entered_ = 0; |
| 244 | return true; |
| 245 | } |
| 246 | } |
| 247 | }; |
| 248 | |
| 249 | // TimerManager for current run. |
| 250 | static std::unique_ptr<TimerManager> timer_manager = nullptr; |
| 251 | |
| 252 | } // end namespace |
| 253 | |
| 254 | namespace internal { |
| 255 | |
| 256 | // Information kept per benchmark we may want to run |
| 257 | struct Benchmark::Instance { |
| 258 | std::string name; |
| 259 | Benchmark* benchmark; |
| 260 | bool has_arg1; |
| 261 | int arg1; |
| 262 | bool has_arg2; |
| 263 | int arg2; |
| 264 | bool use_real_time; |
| 265 | double min_time; |
| 266 | int threads; // Number of concurrent threads to use |
| 267 | bool multithreaded; // Is benchmark multi-threaded? |
| 268 | }; |
| 269 | |
| 270 | // Class for managing registered benchmarks. Note that each registered |
| 271 | // benchmark identifies a family of related benchmarks to run. |
| 272 | class BenchmarkFamilies { |
| 273 | public: |
| 274 | static BenchmarkFamilies* GetInstance(); |
| 275 | |
| 276 | // Registers a benchmark family and returns the index assigned to it. |
| 277 | size_t AddBenchmark(std::unique_ptr<Benchmark> family); |
| 278 | |
| 279 | // Extract the list of benchmark instances that match the specified |
| 280 | // regular expression. |
| 281 | bool FindBenchmarks(const std::string& re, |
| 282 | std::vector<Benchmark::Instance>* benchmarks); |
| 283 | private: |
| 284 | BenchmarkFamilies() {} |
| 285 | |
| 286 | std::vector<std::unique_ptr<Benchmark>> families_; |
| 287 | Mutex mutex_; |
| 288 | }; |
| 289 | |
| 290 | |
| 291 | class BenchmarkImp { |
| 292 | public: |
| 293 | explicit BenchmarkImp(const char* name); |
| 294 | ~BenchmarkImp(); |
| 295 | |
| 296 | void Arg(int x); |
| 297 | void Range(int start, int limit); |
| 298 | void DenseRange(int start, int limit); |
| 299 | void ArgPair(int start, int limit); |
| 300 | void RangePair(int lo1, int hi1, int lo2, int hi2); |
| 301 | void MinTime(double n); |
| 302 | void UseRealTime(); |
| 303 | void Threads(int t); |
| 304 | void ThreadRange(int min_threads, int max_threads); |
| 305 | void ThreadPerCpu(); |
| 306 | void SetName(const char* name); |
| 307 | |
| 308 | static void AddRange(std::vector<int>* dst, int lo, int hi, int mult); |
| 309 | |
| 310 | private: |
| 311 | friend class BenchmarkFamilies; |
| 312 | |
| 313 | std::string name_; |
| 314 | int arg_count_; |
| 315 | std::vector< std::pair<int, int> > args_; // Args for all benchmark runs |
| 316 | double min_time_; |
| 317 | bool use_real_time_; |
| 318 | std::vector<int> thread_counts_; |
| 319 | |
| 320 | BenchmarkImp& operator=(BenchmarkImp const&); |
| 321 | }; |
| 322 | |
| 323 | BenchmarkFamilies* BenchmarkFamilies::GetInstance() { |
| 324 | static BenchmarkFamilies instance; |
| 325 | return &instance; |
| 326 | } |
| 327 | |
| 328 | |
| 329 | size_t BenchmarkFamilies::AddBenchmark(std::unique_ptr<Benchmark> family) { |
| 330 | MutexLock l(mutex_); |
| 331 | size_t index = families_.size(); |
| 332 | families_.push_back(std::move(family)); |
| 333 | return index; |
| 334 | } |
| 335 | |
| 336 | bool BenchmarkFamilies::FindBenchmarks( |
| 337 | const std::string& spec, |
| 338 | std::vector<Benchmark::Instance>* benchmarks) { |
| 339 | // Make regular expression out of command-line flag |
| 340 | std::string error_msg; |
| 341 | Regex re; |
| 342 | if (!re.Init(spec, &error_msg)) { |
| 343 | std::cerr << "Could not compile benchmark re: " << error_msg << std::endl; |
| 344 | return false; |
| 345 | } |
| 346 | |
| 347 | // Special list of thread counts to use when none are specified |
| 348 | std::vector<int> one_thread; |
| 349 | one_thread.push_back(1); |
| 350 | |
| 351 | MutexLock l(mutex_); |
| 352 | for (std::unique_ptr<Benchmark>& bench_family : families_) { |
| 353 | // Family was deleted or benchmark doesn't match |
| 354 | if (!bench_family) continue; |
| 355 | BenchmarkImp* family = bench_family->imp_; |
| 356 | |
| 357 | if (family->arg_count_ == -1) { |
| 358 | family->arg_count_ = 0; |
| 359 | family->args_.emplace_back(-1, -1); |
| 360 | } |
| 361 | for (auto const& args : family->args_) { |
| 362 | const std::vector<int>* thread_counts = |
| 363 | (family->thread_counts_.empty() |
| 364 | ? &one_thread |
| 365 | : &family->thread_counts_); |
| 366 | for (int num_threads : *thread_counts) { |
| 367 | |
| 368 | Benchmark::Instance instance; |
| 369 | instance.name = family->name_; |
| 370 | instance.benchmark = bench_family.get(); |
| 371 | instance.has_arg1 = family->arg_count_ >= 1; |
| 372 | instance.arg1 = args.first; |
| 373 | instance.has_arg2 = family->arg_count_ == 2; |
| 374 | instance.arg2 = args.second; |
| 375 | instance.min_time = family->min_time_; |
| 376 | instance.use_real_time = family->use_real_time_; |
| 377 | instance.threads = num_threads; |
| 378 | instance.multithreaded = !(family->thread_counts_.empty()); |
| 379 | |
| 380 | // Add arguments to instance name |
| 381 | if (family->arg_count_ >= 1) { |
| 382 | AppendHumanReadable(instance.arg1, &instance.name); |
| 383 | } |
| 384 | if (family->arg_count_ >= 2) { |
| 385 | AppendHumanReadable(instance.arg2, &instance.name); |
| 386 | } |
| 387 | if (!IsZero(family->min_time_)) { |
| 388 | instance.name += StringPrintF("/min_time:%0.3f", family->min_time_); |
| 389 | } |
| 390 | if (family->use_real_time_) { |
| 391 | instance.name += "/real_time"; |
| 392 | } |
| 393 | |
| 394 | // Add the number of threads used to the name |
| 395 | if (!family->thread_counts_.empty()) { |
| 396 | instance.name += StringPrintF("/threads:%d", instance.threads); |
| 397 | } |
| 398 | |
| 399 | if (re.Match(instance.name)) { |
| 400 | benchmarks->push_back(instance); |
| 401 | } |
| 402 | } |
| 403 | } |
| 404 | } |
| 405 | return true; |
| 406 | } |
| 407 | |
| 408 | BenchmarkImp::BenchmarkImp(const char* name) |
| 409 | : name_(name), arg_count_(-1), |
| 410 | min_time_(0.0), use_real_time_(false) { |
| 411 | } |
| 412 | |
| 413 | BenchmarkImp::~BenchmarkImp() { |
| 414 | } |
| 415 | |
| 416 | void BenchmarkImp::Arg(int x) { |
| 417 | CHECK(arg_count_ == -1 || arg_count_ == 1); |
| 418 | arg_count_ = 1; |
| 419 | args_.emplace_back(x, -1); |
| 420 | } |
| 421 | |
| 422 | void BenchmarkImp::Range(int start, int limit) { |
| 423 | CHECK(arg_count_ == -1 || arg_count_ == 1); |
| 424 | arg_count_ = 1; |
| 425 | std::vector<int> arglist; |
| 426 | AddRange(&arglist, start, limit, kRangeMultiplier); |
| 427 | |
| 428 | for (int i : arglist) { |
| 429 | args_.emplace_back(i, -1); |
| 430 | } |
| 431 | } |
| 432 | |
| 433 | void BenchmarkImp::DenseRange(int start, int limit) { |
| 434 | CHECK(arg_count_ == -1 || arg_count_ == 1); |
| 435 | arg_count_ = 1; |
| 436 | CHECK_GE(start, 0); |
| 437 | CHECK_LE(start, limit); |
| 438 | for (int arg = start; arg <= limit; arg++) { |
| 439 | args_.emplace_back(arg, -1); |
| 440 | } |
| 441 | } |
| 442 | |
| 443 | void BenchmarkImp::ArgPair(int x, int y) { |
| 444 | CHECK(arg_count_ == -1 || arg_count_ == 2); |
| 445 | arg_count_ = 2; |
| 446 | args_.emplace_back(x, y); |
| 447 | } |
| 448 | |
| 449 | void BenchmarkImp::RangePair(int lo1, int hi1, int lo2, int hi2) { |
| 450 | CHECK(arg_count_ == -1 || arg_count_ == 2); |
| 451 | arg_count_ = 2; |
| 452 | std::vector<int> arglist1, arglist2; |
| 453 | AddRange(&arglist1, lo1, hi1, kRangeMultiplier); |
| 454 | AddRange(&arglist2, lo2, hi2, kRangeMultiplier); |
| 455 | |
| 456 | for (int i : arglist1) { |
| 457 | for (int j : arglist2) { |
| 458 | args_.emplace_back(i, j); |
| 459 | } |
| 460 | } |
| 461 | } |
| 462 | |
| 463 | void BenchmarkImp::MinTime(double t) { |
| 464 | CHECK(t > 0.0); |
| 465 | min_time_ = t; |
| 466 | } |
| 467 | |
| 468 | void BenchmarkImp::UseRealTime() { |
| 469 | use_real_time_ = true; |
| 470 | } |
| 471 | |
| 472 | void BenchmarkImp::Threads(int t) { |
| 473 | CHECK_GT(t, 0); |
| 474 | thread_counts_.push_back(t); |
| 475 | } |
| 476 | |
| 477 | void BenchmarkImp::ThreadRange(int min_threads, int max_threads) { |
| 478 | CHECK_GT(min_threads, 0); |
| 479 | CHECK_GE(max_threads, min_threads); |
| 480 | |
| 481 | AddRange(&thread_counts_, min_threads, max_threads, 2); |
| 482 | } |
| 483 | |
| 484 | void BenchmarkImp::ThreadPerCpu() { |
| 485 | static int num_cpus = NumCPUs(); |
| 486 | thread_counts_.push_back(num_cpus); |
| 487 | } |
| 488 | |
| 489 | void BenchmarkImp::SetName(const char* name) { |
| 490 | name_ = name; |
| 491 | } |
| 492 | |
| 493 | void BenchmarkImp::AddRange(std::vector<int>* dst, int lo, int hi, int mult) { |
| 494 | CHECK_GE(lo, 0); |
| 495 | CHECK_GE(hi, lo); |
| 496 | |
| 497 | // Add "lo" |
| 498 | dst->push_back(lo); |
| 499 | |
| 500 | static const int kint32max = std::numeric_limits<int32_t>::max(); |
| 501 | |
| 502 | // Now space out the benchmarks in multiples of "mult" |
| 503 | for (int32_t i = 1; i < kint32max/mult; i *= mult) { |
| 504 | if (i >= hi) break; |
| 505 | if (i > lo) { |
| 506 | dst->push_back(i); |
| 507 | } |
| 508 | } |
| 509 | // Add "hi" (if different from "lo") |
| 510 | if (hi != lo) { |
| 511 | dst->push_back(hi); |
| 512 | } |
| 513 | } |
| 514 | |
| 515 | Benchmark::Benchmark(const char* name) |
| 516 | : imp_(new BenchmarkImp(name)) |
| 517 | { |
| 518 | } |
| 519 | |
| 520 | Benchmark::~Benchmark() { |
| 521 | delete imp_; |
| 522 | } |
| 523 | |
| 524 | Benchmark::Benchmark(Benchmark const& other) |
| 525 | : imp_(new BenchmarkImp(*other.imp_)) |
| 526 | { |
| 527 | } |
| 528 | |
| 529 | Benchmark* Benchmark::Arg(int x) { |
| 530 | imp_->Arg(x); |
| 531 | return this; |
| 532 | } |
| 533 | |
| 534 | Benchmark* Benchmark::Range(int start, int limit) { |
| 535 | imp_->Range(start, limit); |
| 536 | return this; |
| 537 | } |
| 538 | |
| 539 | Benchmark* Benchmark::DenseRange(int start, int limit) { |
| 540 | imp_->DenseRange(start, limit); |
| 541 | return this; |
| 542 | } |
| 543 | |
| 544 | Benchmark* Benchmark::ArgPair(int x, int y) { |
| 545 | imp_->ArgPair(x, y); |
| 546 | return this; |
| 547 | } |
| 548 | |
| 549 | Benchmark* Benchmark::RangePair(int lo1, int hi1, int lo2, int hi2) { |
| 550 | imp_->RangePair(lo1, hi1, lo2, hi2); |
| 551 | return this; |
| 552 | } |
| 553 | |
| 554 | Benchmark* Benchmark::Apply(void (*custom_arguments)(Benchmark* benchmark)) { |
| 555 | custom_arguments(this); |
| 556 | return this; |
| 557 | } |
| 558 | |
| 559 | Benchmark* Benchmark::MinTime(double t) { |
| 560 | imp_->MinTime(t); |
| 561 | return this; |
| 562 | } |
| 563 | |
| 564 | Benchmark* Benchmark::UseRealTime() { |
| 565 | imp_->UseRealTime(); |
| 566 | return this; |
| 567 | } |
| 568 | |
| 569 | Benchmark* Benchmark::Threads(int t) { |
| 570 | imp_->Threads(t); |
| 571 | return this; |
| 572 | } |
| 573 | |
| 574 | Benchmark* Benchmark::ThreadRange(int min_threads, int max_threads) { |
| 575 | imp_->ThreadRange(min_threads, max_threads); |
| 576 | return this; |
| 577 | } |
| 578 | |
| 579 | Benchmark* Benchmark::ThreadPerCpu() { |
| 580 | imp_->ThreadPerCpu(); |
| 581 | return this; |
| 582 | } |
| 583 | |
| 584 | void Benchmark::SetName(const char* name) { |
| 585 | imp_->SetName(name); |
| 586 | } |
| 587 | |
| 588 | void FunctionBenchmark::Run(State& st) { |
| 589 | func_(st); |
| 590 | } |
| 591 | |
| 592 | } // end namespace internal |
| 593 | |
| 594 | namespace { |
| 595 | |
| 596 | |
| 597 | // Execute one thread of benchmark b for the specified number of iterations. |
| 598 | // Adds the stats collected for the thread into *total. |
| 599 | void RunInThread(const benchmark::internal::Benchmark::Instance* b, |
| 600 | size_t iters, int thread_id, |
| 601 | ThreadStats* total) EXCLUDES(GetBenchmarkLock()) { |
| 602 | State st(iters, b->has_arg1, b->arg1, b->has_arg2, b->arg2, thread_id); |
| 603 | b->benchmark->Run(st); |
| 604 | CHECK(st.iterations() == st.max_iterations) << |
| 605 | "Benchmark returned before State::KeepRunning() returned false!"; |
| 606 | { |
| 607 | MutexLock l(GetBenchmarkLock()); |
| 608 | total->bytes_processed += st.bytes_processed(); |
| 609 | total->items_processed += st.items_processed(); |
| 610 | } |
| 611 | |
| 612 | timer_manager->Finalize(); |
| 613 | } |
| 614 | |
| 615 | void RunBenchmark(const benchmark::internal::Benchmark::Instance& b, |
| 616 | BenchmarkReporter* br) EXCLUDES(GetBenchmarkLock()) { |
| 617 | size_t iters = 1; |
| 618 | |
| 619 | std::vector<BenchmarkReporter::Run> reports; |
| 620 | |
| 621 | std::vector<std::thread> pool; |
| 622 | if (b.multithreaded) |
| 623 | pool.resize(b.threads); |
| 624 | |
| 625 | for (int i = 0; i < FLAGS_benchmark_repetitions; i++) { |
| 626 | std::string mem; |
| 627 | for (;;) { |
| 628 | // Try benchmark |
| 629 | VLOG(2) << "Running " << b.name << " for " << iters << "\n"; |
| 630 | |
| 631 | { |
| 632 | MutexLock l(GetBenchmarkLock()); |
| 633 | GetReportLabel()->clear(); |
| 634 | } |
| 635 | |
| 636 | Notification done; |
| 637 | timer_manager = std::unique_ptr<TimerManager>(new TimerManager(b.threads, &done)); |
| 638 | |
| 639 | ThreadStats total; |
| 640 | running_benchmark = true; |
| 641 | if (b.multithreaded) { |
| 642 | // If this is out first iteration of the while(true) loop then the |
| 643 | // threads haven't been started and can't be joined. Otherwise we need |
| 644 | // to join the thread before replacing them. |
| 645 | for (std::thread& thread : pool) { |
| 646 | if (thread.joinable()) |
| 647 | thread.join(); |
| 648 | } |
| 649 | for (std::size_t ti = 0; ti < pool.size(); ++ti) { |
| 650 | pool[ti] = std::thread(&RunInThread, &b, iters, ti, &total); |
| 651 | } |
| 652 | } else { |
| 653 | // Run directly in this thread |
| 654 | RunInThread(&b, iters, 0, &total); |
| 655 | } |
| 656 | done.WaitForNotification(); |
| 657 | running_benchmark = false; |
| 658 | |
| 659 | const double cpu_accumulated_time = timer_manager->cpu_time_used(); |
| 660 | const double real_accumulated_time = timer_manager->real_time_used(); |
| 661 | timer_manager.reset(); |
| 662 | |
| 663 | VLOG(2) << "Ran in " << cpu_accumulated_time << "/" |
| 664 | << real_accumulated_time << "\n"; |
| 665 | |
| 666 | // Base decisions off of real time if requested by this benchmark. |
| 667 | double seconds = cpu_accumulated_time; |
| 668 | if (b.use_real_time) { |
| 669 | seconds = real_accumulated_time; |
| 670 | } |
| 671 | |
| 672 | std::string label; |
| 673 | { |
| 674 | MutexLock l(GetBenchmarkLock()); |
| 675 | label = *GetReportLabel(); |
| 676 | } |
| 677 | |
| 678 | const double min_time = !IsZero(b.min_time) ? b.min_time |
| 679 | : FLAGS_benchmark_min_time; |
| 680 | |
| 681 | // If this was the first run, was elapsed time or cpu time large enough? |
| 682 | // If this is not the first run, go with the current value of iter. |
| 683 | if ((i > 0) || |
| 684 | (iters >= kMaxIterations) || |
| 685 | (seconds >= min_time) || |
| 686 | (real_accumulated_time >= 5*min_time)) { |
| 687 | double bytes_per_second = 0; |
| 688 | if (total.bytes_processed > 0 && seconds > 0.0) { |
| 689 | bytes_per_second = (total.bytes_processed / seconds); |
| 690 | } |
| 691 | double items_per_second = 0; |
| 692 | if (total.items_processed > 0 && seconds > 0.0) { |
| 693 | items_per_second = (total.items_processed / seconds); |
| 694 | } |
| 695 | |
| 696 | // Create report about this benchmark run. |
| 697 | BenchmarkReporter::Run report; |
| 698 | report.benchmark_name = b.name; |
| 699 | report.report_label = label; |
| 700 | // Report the total iterations across all threads. |
| 701 | report.iterations = static_cast<int64_t>(iters) * b.threads; |
| 702 | report.real_accumulated_time = real_accumulated_time; |
| 703 | report.cpu_accumulated_time = cpu_accumulated_time; |
| 704 | report.bytes_per_second = bytes_per_second; |
| 705 | report.items_per_second = items_per_second; |
| 706 | reports.push_back(report); |
| 707 | break; |
| 708 | } |
| 709 | |
| 710 | // See how much iterations should be increased by |
| 711 | // Note: Avoid division by zero with max(seconds, 1ns). |
| 712 | double multiplier = min_time * 1.4 / std::max(seconds, 1e-9); |
| 713 | // If our last run was at least 10% of FLAGS_benchmark_min_time then we |
| 714 | // use the multiplier directly. Otherwise we use at most 10 times |
| 715 | // expansion. |
| 716 | // NOTE: When the last run was at least 10% of the min time the max |
| 717 | // expansion should be 14x. |
| 718 | bool is_significant = (seconds / min_time) > 0.1; |
| 719 | multiplier = is_significant ? multiplier : std::min(10.0, multiplier); |
| 720 | if (multiplier <= 1.0) multiplier = 2.0; |
| 721 | double next_iters = std::max(multiplier * iters, iters + 1.0); |
| 722 | if (next_iters > kMaxIterations) { |
| 723 | next_iters = kMaxIterations; |
| 724 | } |
| 725 | VLOG(3) << "Next iters: " << next_iters << ", " << multiplier << "\n"; |
| 726 | iters = static_cast<int>(next_iters + 0.5); |
| 727 | } |
| 728 | } |
| 729 | br->ReportRuns(reports); |
| 730 | if (b.multithreaded) { |
| 731 | for (std::thread& thread : pool) |
| 732 | thread.join(); |
| 733 | } |
| 734 | } |
| 735 | |
| 736 | } // namespace |
| 737 | |
| 738 | State::State(size_t max_iters, bool has_x, int x, bool has_y, int y, |
| 739 | int thread_i) |
| 740 | : started_(false), total_iterations_(0), |
| 741 | has_range_x_(has_x), range_x_(x), |
| 742 | has_range_y_(has_y), range_y_(y), |
| 743 | bytes_processed_(0), items_processed_(0), |
| 744 | thread_index(thread_i), |
| 745 | max_iterations(max_iters) |
| 746 | { |
| 747 | CHECK(max_iterations != 0) << "At least one iteration must be run"; |
| 748 | } |
| 749 | |
| 750 | void State::PauseTiming() { |
| 751 | // Add in time accumulated so far |
| 752 | CHECK(running_benchmark); |
| 753 | timer_manager->StopTimer(); |
| 754 | } |
| 755 | |
| 756 | void State::ResumeTiming() { |
| 757 | CHECK(running_benchmark); |
| 758 | timer_manager->StartTimer(); |
| 759 | } |
| 760 | |
| 761 | void State::SetLabel(const char* label) { |
| 762 | CHECK(running_benchmark); |
| 763 | MutexLock l(GetBenchmarkLock()); |
| 764 | *GetReportLabel() = label; |
| 765 | } |
| 766 | |
| 767 | namespace internal { |
| 768 | namespace { |
| 769 | |
| 770 | void PrintBenchmarkList() { |
| 771 | std::vector<Benchmark::Instance> benchmarks; |
| 772 | auto families = BenchmarkFamilies::GetInstance(); |
| 773 | if (!families->FindBenchmarks(".", &benchmarks)) return; |
| 774 | |
| 775 | for (const internal::Benchmark::Instance& benchmark : benchmarks) { |
| 776 | std::cout << benchmark.name << "\n"; |
| 777 | } |
| 778 | } |
| 779 | |
| 780 | void RunMatchingBenchmarks(const std::string& spec, |
| 781 | BenchmarkReporter* reporter) { |
| 782 | CHECK(reporter != nullptr); |
| 783 | if (spec.empty()) return; |
| 784 | |
| 785 | std::vector<Benchmark::Instance> benchmarks; |
| 786 | auto families = BenchmarkFamilies::GetInstance(); |
| 787 | if (!families->FindBenchmarks(spec, &benchmarks)) return; |
| 788 | |
| 789 | // Determine the width of the name field using a minimum width of 10. |
| 790 | size_t name_field_width = 10; |
| 791 | for (const Benchmark::Instance& benchmark : benchmarks) { |
| 792 | name_field_width = |
| 793 | std::max<size_t>(name_field_width, benchmark.name.size()); |
| 794 | } |
| 795 | if (FLAGS_benchmark_repetitions > 1) |
| 796 | name_field_width += std::strlen("_stddev"); |
| 797 | |
| 798 | // Print header here |
| 799 | BenchmarkReporter::Context context; |
| 800 | context.num_cpus = NumCPUs(); |
| 801 | context.mhz_per_cpu = CyclesPerSecond() / 1000000.0f; |
| 802 | |
| 803 | context.cpu_scaling_enabled = CpuScalingEnabled(); |
| 804 | context.name_field_width = name_field_width; |
| 805 | |
| 806 | if (reporter->ReportContext(context)) { |
| 807 | for (const auto& benchmark : benchmarks) { |
| 808 | RunBenchmark(benchmark, reporter); |
| 809 | } |
| 810 | } |
| 811 | } |
| 812 | |
| 813 | std::unique_ptr<BenchmarkReporter> GetDefaultReporter() { |
| 814 | typedef std::unique_ptr<BenchmarkReporter> PtrType; |
| 815 | if (FLAGS_benchmark_format == "tabular") { |
| 816 | return PtrType(new ConsoleReporter); |
| 817 | } else if (FLAGS_benchmark_format == "json") { |
| 818 | return PtrType(new JSONReporter); |
| 819 | } else if (FLAGS_benchmark_format == "csv") { |
| 820 | return PtrType(new CSVReporter); |
| 821 | } else { |
| 822 | std::cerr << "Unexpected format: '" << FLAGS_benchmark_format << "'\n"; |
| 823 | std::exit(1); |
| 824 | } |
| 825 | } |
| 826 | |
| 827 | } // end namespace |
| 828 | } // end namespace internal |
| 829 | |
| 830 | void RunSpecifiedBenchmarks() { |
| 831 | RunSpecifiedBenchmarks(nullptr); |
| 832 | } |
| 833 | |
| 834 | void RunSpecifiedBenchmarks(BenchmarkReporter* reporter) { |
| 835 | if (FLAGS_benchmark_list_tests) { |
| 836 | internal::PrintBenchmarkList(); |
| 837 | return; |
| 838 | } |
| 839 | std::string spec = FLAGS_benchmark_filter; |
| 840 | if (spec.empty() || spec == "all") |
| 841 | spec = "."; // Regexp that matches all benchmarks |
| 842 | |
| 843 | std::unique_ptr<BenchmarkReporter> default_reporter; |
| 844 | if (!reporter) { |
| 845 | default_reporter = internal::GetDefaultReporter(); |
| 846 | reporter = default_reporter.get(); |
| 847 | } |
| 848 | internal::RunMatchingBenchmarks(spec, reporter); |
| 849 | reporter->Finalize(); |
| 850 | } |
| 851 | |
| 852 | namespace internal { |
| 853 | |
| 854 | void PrintUsageAndExit() { |
| 855 | fprintf(stdout, |
| 856 | "benchmark" |
| 857 | " [--benchmark_list_tests={true|false}]\n" |
| 858 | " [--benchmark_filter=<regex>]\n" |
| 859 | " [--benchmark_min_time=<min_time>]\n" |
| 860 | " [--benchmark_repetitions=<num_repetitions>]\n" |
| 861 | " [--benchmark_format=<tabular|json|csv>]\n" |
| 862 | " [--color_print={true|false}]\n" |
| 863 | " [--v=<verbosity>]\n"); |
| 864 | exit(0); |
| 865 | } |
| 866 | |
| 867 | void ParseCommandLineFlags(int* argc, char** argv) { |
| 868 | using namespace benchmark; |
| 869 | for (int i = 1; i < *argc; ++i) { |
| 870 | if ( |
| 871 | ParseBoolFlag(argv[i], "benchmark_list_tests", |
| 872 | &FLAGS_benchmark_list_tests) || |
| 873 | ParseStringFlag(argv[i], "benchmark_filter", |
| 874 | &FLAGS_benchmark_filter) || |
| 875 | ParseDoubleFlag(argv[i], "benchmark_min_time", |
| 876 | &FLAGS_benchmark_min_time) || |
| 877 | ParseInt32Flag(argv[i], "benchmark_repetitions", |
| 878 | &FLAGS_benchmark_repetitions) || |
| 879 | ParseStringFlag(argv[i], "benchmark_format", |
| 880 | &FLAGS_benchmark_format) || |
| 881 | ParseBoolFlag(argv[i], "color_print", |
| 882 | &FLAGS_color_print) || |
| 883 | ParseInt32Flag(argv[i], "v", &FLAGS_v)) { |
| 884 | for (int j = i; j != *argc; ++j) argv[j] = argv[j + 1]; |
| 885 | |
| 886 | --(*argc); |
| 887 | --i; |
| 888 | } else if (IsFlag(argv[i], "help")) { |
| 889 | PrintUsageAndExit(); |
| 890 | } |
| 891 | } |
| 892 | if (FLAGS_benchmark_format != "tabular" && |
| 893 | FLAGS_benchmark_format != "json" && |
| 894 | FLAGS_benchmark_format != "csv") { |
| 895 | PrintUsageAndExit(); |
| 896 | } |
| 897 | } |
| 898 | |
| 899 | Benchmark* RegisterBenchmarkInternal(Benchmark* bench) { |
| 900 | std::unique_ptr<Benchmark> bench_ptr(bench); |
| 901 | BenchmarkFamilies* families = BenchmarkFamilies::GetInstance(); |
| 902 | families->AddBenchmark(std::move(bench_ptr)); |
| 903 | return bench; |
| 904 | } |
| 905 | |
| 906 | } // end namespace internal |
| 907 | |
| 908 | void Initialize(int* argc, char** argv) { |
| 909 | internal::ParseCommandLineFlags(argc, argv); |
| 910 | internal::SetLogLevel(FLAGS_v); |
| 911 | // TODO remove this. It prints some output the first time it is called. |
| 912 | // We don't want to have this ouput printed during benchmarking. |
| 913 | MyCPUUsage(); |
| 914 | // The first call to walltime::Now initialized it. Call it once to |
| 915 | // prevent the initialization from happening in a benchmark. |
| 916 | walltime::Now(); |
| 917 | } |
| 918 | |
| 919 | } // end namespace benchmark |
trunk/3rdparty/benchmark/src/commandlineflags.cc
| r0 | r253077 | |
| 1 | // Copyright 2015 Google Inc. All rights reserved. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | #include "commandlineflags.h" |
| 16 | |
| 17 | #include <cstdlib> |
| 18 | #include <cstring> |
| 19 | #include <iostream> |
| 20 | #include <limits> |
| 21 | |
| 22 | namespace benchmark { |
| 23 | // Parses 'str' for a 32-bit signed integer. If successful, writes |
| 24 | // the result to *value and returns true; otherwise leaves *value |
| 25 | // unchanged and returns false. |
| 26 | bool ParseInt32(const std::string& src_text, const char* str, int32_t* value) { |
| 27 | // Parses the environment variable as a decimal integer. |
| 28 | char* end = nullptr; |
| 29 | const long long_value = strtol(str, &end, 10); // NOLINT |
| 30 | |
| 31 | // Has strtol() consumed all characters in the string? |
| 32 | if (*end != '\0') { |
| 33 | // No - an invalid character was encountered. |
| 34 | std::cerr << src_text << " is expected to be a 32-bit integer, " |
| 35 | << "but actually has value \"" << str << "\".\n"; |
| 36 | return false; |
| 37 | } |
| 38 | |
| 39 | // Is the parsed value in the range of an Int32? |
| 40 | const int32_t result = static_cast<int32_t>(long_value); |
| 41 | if (long_value == std::numeric_limits<long>::max() || |
| 42 | long_value == std::numeric_limits<long>::min() || |
| 43 | // The parsed value overflows as a long. (strtol() returns |
| 44 | // LONG_MAX or LONG_MIN when the input overflows.) |
| 45 | result != long_value |
| 46 | // The parsed value overflows as an Int32. |
| 47 | ) { |
| 48 | std::cerr << src_text << " is expected to be a 32-bit integer, " |
| 49 | << "but actually has value \"" << str << "\", " |
| 50 | << "which overflows.\n"; |
| 51 | return false; |
| 52 | } |
| 53 | |
| 54 | *value = result; |
| 55 | return true; |
| 56 | } |
| 57 | |
| 58 | // Parses 'str' for a double. If successful, writes the result to *value and |
| 59 | // returns true; otherwise leaves *value unchanged and returns false. |
| 60 | bool ParseDouble(const std::string& src_text, const char* str, double* value) { |
| 61 | // Parses the environment variable as a decimal integer. |
| 62 | char* end = nullptr; |
| 63 | const double double_value = strtod(str, &end); // NOLINT |
| 64 | |
| 65 | // Has strtol() consumed all characters in the string? |
| 66 | if (*end != '\0') { |
| 67 | // No - an invalid character was encountered. |
| 68 | std::cerr << src_text << " is expected to be a double, " |
| 69 | << "but actually has value \"" << str << "\".\n"; |
| 70 | return false; |
| 71 | } |
| 72 | |
| 73 | *value = double_value; |
| 74 | return true; |
| 75 | } |
| 76 | |
| 77 | inline const char* GetEnv(const char* name) { |
| 78 | #if defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) |
| 79 | // Environment variables which we programmatically clear will be set to the |
| 80 | // empty string rather than unset (nullptr). Handle that case. |
| 81 | const char* const env = getenv(name); |
| 82 | return (env != nullptr && env[0] != '\0') ? env : nullptr; |
| 83 | #else |
| 84 | return getenv(name); |
| 85 | #endif |
| 86 | } |
| 87 | |
| 88 | // Returns the name of the environment variable corresponding to the |
| 89 | // given flag. For example, FlagToEnvVar("foo") will return |
| 90 | // "BENCHMARK_FOO" in the open-source version. |
| 91 | static std::string FlagToEnvVar(const char* flag) { |
| 92 | const std::string flag_str(flag); |
| 93 | |
| 94 | std::string env_var; |
| 95 | for (size_t i = 0; i != flag_str.length(); ++i) |
| 96 | env_var += static_cast<char>(::toupper(flag_str.c_str()[i])); |
| 97 | |
| 98 | return "BENCHMARK_" + env_var; |
| 99 | } |
| 100 | |
| 101 | // Reads and returns the Boolean environment variable corresponding to |
| 102 | // the given flag; if it's not set, returns default_value. |
| 103 | // |
| 104 | // The value is considered true iff it's not "0". |
| 105 | bool BoolFromEnv(const char* flag, bool default_value) { |
| 106 | const std::string env_var = FlagToEnvVar(flag); |
| 107 | const char* const string_value = GetEnv(env_var.c_str()); |
| 108 | return string_value == nullptr ? default_value : strcmp(string_value, "0") != 0; |
| 109 | } |
| 110 | |
| 111 | // Reads and returns a 32-bit integer stored in the environment |
| 112 | // variable corresponding to the given flag; if it isn't set or |
| 113 | // doesn't represent a valid 32-bit integer, returns default_value. |
| 114 | int32_t Int32FromEnv(const char* flag, int32_t default_value) { |
| 115 | const std::string env_var = FlagToEnvVar(flag); |
| 116 | const char* const string_value = GetEnv(env_var.c_str()); |
| 117 | if (string_value == nullptr) { |
| 118 | // The environment variable is not set. |
| 119 | return default_value; |
| 120 | } |
| 121 | |
| 122 | int32_t result = default_value; |
| 123 | if (!ParseInt32(std::string("Environment variable ") + env_var, string_value, |
| 124 | &result)) { |
| 125 | std::cout << "The default value " << default_value << " is used.\n"; |
| 126 | return default_value; |
| 127 | } |
| 128 | |
| 129 | return result; |
| 130 | } |
| 131 | |
| 132 | // Reads and returns the string environment variable corresponding to |
| 133 | // the given flag; if it's not set, returns default_value. |
| 134 | const char* StringFromEnv(const char* flag, const char* default_value) { |
| 135 | const std::string env_var = FlagToEnvVar(flag); |
| 136 | const char* const value = GetEnv(env_var.c_str()); |
| 137 | return value == nullptr ? default_value : value; |
| 138 | } |
| 139 | |
| 140 | // Parses a string as a command line flag. The string should have |
| 141 | // the format "--flag=value". When def_optional is true, the "=value" |
| 142 | // part can be omitted. |
| 143 | // |
| 144 | // Returns the value of the flag, or nullptr if the parsing failed. |
| 145 | const char* ParseFlagValue(const char* str, const char* flag, |
| 146 | bool def_optional) { |
| 147 | // str and flag must not be nullptr. |
| 148 | if (str == nullptr || flag == nullptr) return nullptr; |
| 149 | |
| 150 | // The flag must start with "--". |
| 151 | const std::string flag_str = std::string("--") + std::string(flag); |
| 152 | const size_t flag_len = flag_str.length(); |
| 153 | if (strncmp(str, flag_str.c_str(), flag_len) != 0) return nullptr; |
| 154 | |
| 155 | // Skips the flag name. |
| 156 | const char* flag_end = str + flag_len; |
| 157 | |
| 158 | // When def_optional is true, it's OK to not have a "=value" part. |
| 159 | if (def_optional && (flag_end[0] == '\0')) return flag_end; |
| 160 | |
| 161 | // If def_optional is true and there are more characters after the |
| 162 | // flag name, or if def_optional is false, there must be a '=' after |
| 163 | // the flag name. |
| 164 | if (flag_end[0] != '=') return nullptr; |
| 165 | |
| 166 | // Returns the string after "=". |
| 167 | return flag_end + 1; |
| 168 | } |
| 169 | |
| 170 | bool ParseBoolFlag(const char* str, const char* flag, bool* value) { |
| 171 | // Gets the value of the flag as a string. |
| 172 | const char* const value_str = ParseFlagValue(str, flag, true); |
| 173 | |
| 174 | // Aborts if the parsing failed. |
| 175 | if (value_str == nullptr) return false; |
| 176 | |
| 177 | // Converts the string value to a bool. |
| 178 | *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); |
| 179 | return true; |
| 180 | } |
| 181 | |
| 182 | bool ParseInt32Flag(const char* str, const char* flag, int32_t* value) { |
| 183 | // Gets the value of the flag as a string. |
| 184 | const char* const value_str = ParseFlagValue(str, flag, false); |
| 185 | |
| 186 | // Aborts if the parsing failed. |
| 187 | if (value_str == nullptr) return false; |
| 188 | |
| 189 | // Sets *value to the value of the flag. |
| 190 | return ParseInt32(std::string("The value of flag --") + flag, value_str, |
| 191 | value); |
| 192 | } |
| 193 | |
| 194 | bool ParseDoubleFlag(const char* str, const char* flag, double* value) { |
| 195 | // Gets the value of the flag as a string. |
| 196 | const char* const value_str = ParseFlagValue(str, flag, false); |
| 197 | |
| 198 | // Aborts if the parsing failed. |
| 199 | if (value_str == nullptr) return false; |
| 200 | |
| 201 | // Sets *value to the value of the flag. |
| 202 | return ParseDouble(std::string("The value of flag --") + flag, value_str, |
| 203 | value); |
| 204 | } |
| 205 | |
| 206 | bool ParseStringFlag(const char* str, const char* flag, std::string* value) { |
| 207 | // Gets the value of the flag as a string. |
| 208 | const char* const value_str = ParseFlagValue(str, flag, false); |
| 209 | |
| 210 | // Aborts if the parsing failed. |
| 211 | if (value_str == nullptr) return false; |
| 212 | |
| 213 | *value = value_str; |
| 214 | return true; |
| 215 | } |
| 216 | |
| 217 | bool IsFlag(const char* str, const char* flag) { |
| 218 | return (ParseFlagValue(str, flag, true) != nullptr); |
| 219 | } |
| 220 | } // end namespace benchmark |
trunk/3rdparty/benchmark/src/cycleclock.h
| r0 | r253077 | |
| 1 | // ---------------------------------------------------------------------- |
| 2 | // CycleClock |
| 3 | // A CycleClock tells you the current time in Cycles. The "time" |
| 4 | // is actually time since power-on. This is like time() but doesn't |
| 5 | // involve a system call and is much more precise. |
| 6 | // |
| 7 | // NOTE: Not all cpu/platform/kernel combinations guarantee that this |
| 8 | // clock increments at a constant rate or is synchronized across all logical |
| 9 | // cpus in a system. |
| 10 | // |
| 11 | // If you need the above guarantees, please consider using a different |
| 12 | // API. There are efforts to provide an interface which provides a millisecond |
| 13 | // granularity and implemented as a memory read. A memory read is generally |
| 14 | // cheaper than the CycleClock for many architectures. |
| 15 | // |
| 16 | // Also, in some out of order CPU implementations, the CycleClock is not |
| 17 | // serializing. So if you're trying to count at cycles granularity, your |
| 18 | // data might be inaccurate due to out of order instruction execution. |
| 19 | // ---------------------------------------------------------------------- |
| 20 | |
| 21 | #ifndef BENCHMARK_CYCLECLOCK_H_ |
| 22 | #define BENCHMARK_CYCLECLOCK_H_ |
| 23 | |
| 24 | #include <cstdint> |
| 25 | |
| 26 | #include "benchmark/macros.h" |
| 27 | #include "internal_macros.h" |
| 28 | |
| 29 | #if defined(BENCHMARK_OS_MACOSX) |
| 30 | #include <mach/mach_time.h> |
| 31 | #endif |
| 32 | // For MSVC, we want to use '_asm rdtsc' when possible (since it works |
| 33 | // with even ancient MSVC compilers), and when not possible the |
| 34 | // __rdtsc intrinsic, declared in <intrin.h>. Unfortunately, in some |
| 35 | // environments, <windows.h> and <intrin.h> have conflicting |
| 36 | // declarations of some other intrinsics, breaking compilation. |
| 37 | // Therefore, we simply declare __rdtsc ourselves. See also |
| 38 | // http://connect.microsoft.com/VisualStudio/feedback/details/262047 |
| 39 | #if defined(COMPILER_MSVC) && !defined(_M_IX86) |
| 40 | extern "C" uint64_t __rdtsc(); |
| 41 | #pragma intrinsic(__rdtsc) |
| 42 | #endif |
| 43 | |
| 44 | #ifndef BENCHMARK_OS_WINDOWS |
| 45 | #include <sys/time.h> |
| 46 | #endif |
| 47 | |
| 48 | namespace benchmark { |
| 49 | // NOTE: only i386 and x86_64 have been well tested. |
| 50 | // PPC, sparc, alpha, and ia64 are based on |
| 51 | // http://peter.kuscsik.com/wordpress/?p=14 |
| 52 | // with modifications by m3b. See also |
| 53 | // https://setisvn.ssl.berkeley.edu/svn/lib/fftw-3.0.1/kernel/cycle.h |
| 54 | namespace cycleclock { |
| 55 | // This should return the number of cycles since power-on. Thread-safe. |
| 56 | inline BENCHMARK_ALWAYS_INLINE int64_t Now() { |
| 57 | #if defined(BENCHMARK_OS_MACOSX) |
| 58 | // this goes at the top because we need ALL Macs, regardless of |
| 59 | // architecture, to return the number of "mach time units" that |
| 60 | // have passed since startup. See sysinfo.cc where |
| 61 | // InitializeSystemInfo() sets the supposed cpu clock frequency of |
| 62 | // macs to the number of mach time units per second, not actual |
| 63 | // CPU clock frequency (which can change in the face of CPU |
| 64 | // frequency scaling). Also note that when the Mac sleeps, this |
| 65 | // counter pauses; it does not continue counting, nor does it |
| 66 | // reset to zero. |
| 67 | return mach_absolute_time(); |
| 68 | #elif defined(__i386__) |
| 69 | int64_t ret; |
| 70 | __asm__ volatile("rdtsc" : "=A"(ret)); |
| 71 | return ret; |
| 72 | #elif defined(__x86_64__) || defined(__amd64__) |
| 73 | uint64_t low, high; |
| 74 | __asm__ volatile("rdtsc" : "=a"(low), "=d"(high)); |
| 75 | return (high << 32) | low; |
| 76 | #elif defined(__powerpc__) || defined(__ppc__) |
| 77 | // This returns a time-base, which is not always precisely a cycle-count. |
| 78 | int64_t tbl, tbu0, tbu1; |
| 79 | asm("mftbu %0" : "=r"(tbu0)); |
| 80 | asm("mftb %0" : "=r"(tbl)); |
| 81 | asm("mftbu %0" : "=r"(tbu1)); |
| 82 | tbl &= -static_cast<int64>(tbu0 == tbu1); |
| 83 | // high 32 bits in tbu1; low 32 bits in tbl (tbu0 is garbage) |
| 84 | return (tbu1 << 32) | tbl; |
| 85 | #elif defined(__sparc__) |
| 86 | int64_t tick; |
| 87 | asm(".byte 0x83, 0x41, 0x00, 0x00"); |
| 88 | asm("mov %%g1, %0" : "=r"(tick)); |
| 89 | return tick; |
| 90 | #elif defined(__ia64__) |
| 91 | int64_t itc; |
| 92 | asm("mov %0 = ar.itc" : "=r"(itc)); |
| 93 | return itc; |
| 94 | #elif defined(COMPILER_MSVC) && defined(_M_IX86) |
| 95 | // Older MSVC compilers (like 7.x) don't seem to support the |
| 96 | // __rdtsc intrinsic properly, so I prefer to use _asm instead |
| 97 | // when I know it will work. Otherwise, I'll use __rdtsc and hope |
| 98 | // the code is being compiled with a non-ancient compiler. |
| 99 | _asm rdtsc |
| 100 | #elif defined(COMPILER_MSVC) |
| 101 | return __rdtsc(); |
| 102 | #elif defined(__ARM_ARCH) |
| 103 | #if (__ARM_ARCH >= 6) // V6 is the earliest arch that has a standard cyclecount |
| 104 | uint32_t pmccntr; |
| 105 | uint32_t pmuseren; |
| 106 | uint32_t pmcntenset; |
| 107 | // Read the user mode perf monitor counter access permissions. |
| 108 | asm("mrc p15, 0, %0, c9, c14, 0" : "=r"(pmuseren)); |
| 109 | if (pmuseren & 1) { // Allows reading perfmon counters for user mode code. |
| 110 | asm("mrc p15, 0, %0, c9, c12, 1" : "=r"(pmcntenset)); |
| 111 | if (pmcntenset & 0x80000000ul) { // Is it counting? |
| 112 | asm("mrc p15, 0, %0, c9, c13, 0" : "=r"(pmccntr)); |
| 113 | // The counter is set up to count every 64th cycle |
| 114 | return static_cast<int64_t>(pmccntr) * 64; // Should optimize to << 6 |
| 115 | } |
| 116 | } |
| 117 | #endif |
| 118 | struct timeval tv; |
| 119 | gettimeofday(&tv, nullptr); |
| 120 | return static_cast<int64_t>(tv.tv_sec) * 1000000 + tv.tv_usec; |
| 121 | #elif defined(__mips__) |
| 122 | // mips apparently only allows rdtsc for superusers, so we fall |
| 123 | // back to gettimeofday. It's possible clock_gettime would be better. |
| 124 | struct timeval tv; |
| 125 | gettimeofday(&tv, nullptr); |
| 126 | return static_cast<int64_t>(tv.tv_sec) * 1000000 + tv.tv_usec; |
| 127 | #else |
| 128 | // The soft failover to a generic implementation is automatic only for ARM. |
| 129 | // For other platforms the developer is expected to make an attempt to create |
| 130 | // a fast implementation and use generic version if nothing better is available. |
| 131 | #error You need to define CycleTimer for your OS and CPU |
| 132 | #endif |
| 133 | } |
| 134 | } // end namespace cycleclock |
| 135 | } // end namespace benchmark |
| 136 | |
| 137 | #endif // BENCHMARK_CYCLECLOCK_H_ |
trunk/3rdparty/benchmark/src/stat.h
| r0 | r253077 | |
| 1 | #ifndef BENCHMARK_STAT_H_ |
| 2 | #define BENCHMARK_STAT_H_ |
| 3 | |
| 4 | #include <cmath> |
| 5 | #include <limits> |
| 6 | #include <ostream> |
| 7 | #include <type_traits> |
| 8 | |
| 9 | |
| 10 | namespace benchmark { |
| 11 | |
| 12 | template <typename VType, typename NumType> |
| 13 | class Stat1; |
| 14 | |
| 15 | template <typename VType, typename NumType> |
| 16 | class Stat1MinMax; |
| 17 | |
| 18 | typedef Stat1<float, int64_t> Stat1_f; |
| 19 | typedef Stat1<double, int64_t> Stat1_d; |
| 20 | typedef Stat1MinMax<float, int64_t> Stat1MinMax_f; |
| 21 | typedef Stat1MinMax<double, int64_t> Stat1MinMax_d; |
| 22 | |
| 23 | template <typename VType> |
| 24 | class Vector2; |
| 25 | template <typename VType> |
| 26 | class Vector3; |
| 27 | template <typename VType> |
| 28 | class Vector4; |
| 29 | |
| 30 | template <typename VType, typename NumType> |
| 31 | class Stat1 { |
| 32 | public: |
| 33 | typedef Stat1<VType, NumType> Self; |
| 34 | |
| 35 | Stat1() { Clear(); } |
| 36 | // Create a sample of value dat and weight 1 |
| 37 | explicit Stat1(const VType &dat) { |
| 38 | sum_ = dat; |
| 39 | sum_squares_ = Sqr(dat); |
| 40 | numsamples_ = 1; |
| 41 | } |
| 42 | // Create statistics for all the samples between begin (included) |
| 43 | // and end(excluded) |
| 44 | explicit Stat1(const VType *begin, const VType *end) { |
| 45 | Clear(); |
| 46 | for (const VType *item = begin; item < end; ++item) { |
| 47 | (*this) += Stat1(*item); |
| 48 | } |
| 49 | } |
| 50 | // Create a sample of value dat and weight w |
| 51 | Stat1(const VType &dat, const NumType &w) { |
| 52 | sum_ = w * dat; |
| 53 | sum_squares_ = w * Sqr(dat); |
| 54 | numsamples_ = w; |
| 55 | } |
| 56 | // Copy operator |
| 57 | Stat1(const Self &stat) { |
| 58 | sum_ = stat.sum_; |
| 59 | sum_squares_ = stat.sum_squares_; |
| 60 | numsamples_ = stat.numsamples_; |
| 61 | } |
| 62 | |
| 63 | void Clear() { |
| 64 | numsamples_ = NumType(); |
| 65 | sum_squares_ = sum_ = VType(); |
| 66 | } |
| 67 | |
| 68 | Self &operator=(const Self &stat) { |
| 69 | sum_ = stat.sum_; |
| 70 | sum_squares_ = stat.sum_squares_; |
| 71 | numsamples_ = stat.numsamples_; |
| 72 | return (*this); |
| 73 | } |
| 74 | // Merge statistics from two sample sets. |
| 75 | Self &operator+=(const Self &stat) { |
| 76 | sum_ += stat.sum_; |
| 77 | sum_squares_ += stat.sum_squares_; |
| 78 | numsamples_ += stat.numsamples_; |
| 79 | return (*this); |
| 80 | } |
| 81 | // The operation opposite to += |
| 82 | Self &operator-=(const Self &stat) { |
| 83 | sum_ -= stat.sum_; |
| 84 | sum_squares_ -= stat.sum_squares_; |
| 85 | numsamples_ -= stat.numsamples_; |
| 86 | return (*this); |
| 87 | } |
| 88 | // Multiply the weight of the set of samples by a factor k |
| 89 | Self &operator*=(const VType &k) { |
| 90 | sum_ *= k; |
| 91 | sum_squares_ *= k; |
| 92 | numsamples_ *= k; |
| 93 | return (*this); |
| 94 | } |
| 95 | |
| 96 | // Merge statistics from two sample sets. |
| 97 | Self operator+(const Self &stat) const { return Self(*this) += stat; } |
| 98 | |
| 99 | // The operation opposite to + |
| 100 | Self operator-(const Self &stat) const { return Self(*this) -= stat; } |
| 101 | |
| 102 | // Multiply the weight of the set of samples by a factor k |
| 103 | Self operator*(const VType &k) const { return Self(*this) *= k; } |
| 104 | |
| 105 | // Return the total weight of this sample set |
| 106 | NumType numSamples() const { return numsamples_; } |
| 107 | |
| 108 | // Return the sum of this sample set |
| 109 | VType Sum() const { return sum_; } |
| 110 | |
| 111 | // Return the mean of this sample set |
| 112 | VType Mean() const { |
| 113 | if (numsamples_ == 0) return VType(); |
| 114 | return sum_ * (1.0 / numsamples_); |
| 115 | } |
| 116 | |
| 117 | // Return the mean of this sample set and compute the standard deviation at |
| 118 | // the same time. |
| 119 | VType Mean(VType *stddev) const { |
| 120 | if (numsamples_ == 0) return VType(); |
| 121 | VType mean = sum_ * (1.0 / numsamples_); |
| 122 | if (stddev) { |
| 123 | VType avg_squares = sum_squares_ * (1.0 / numsamples_); |
| 124 | *stddev = Sqrt(avg_squares - Sqr(mean)); |
| 125 | } |
| 126 | return mean; |
| 127 | } |
| 128 | |
| 129 | // Return the standard deviation of the sample set |
| 130 | VType StdDev() const { |
| 131 | if (numsamples_ == 0) return VType(); |
| 132 | VType mean = Mean(); |
| 133 | VType avg_squares = sum_squares_ * (1.0 / numsamples_); |
| 134 | return Sqrt(avg_squares - Sqr(mean)); |
| 135 | } |
| 136 | |
| 137 | private: |
| 138 | static_assert(std::is_integral<NumType>::value && |
| 139 | !std::is_same<NumType, bool>::value, |
| 140 | "NumType must be an integral type that is not bool."); |
| 141 | // Let i be the index of the samples provided (using +=) |
| 142 | // and weight[i],value[i] be the data of sample #i |
| 143 | // then the variables have the following meaning: |
| 144 | NumType numsamples_; // sum of weight[i]; |
| 145 | VType sum_; // sum of weight[i]*value[i]; |
| 146 | VType sum_squares_; // sum of weight[i]*value[i]^2; |
| 147 | |
| 148 | // Template function used to square a number. |
| 149 | // For a vector we square all components |
| 150 | template <typename SType> |
| 151 | static inline SType Sqr(const SType &dat) { |
| 152 | return dat * dat; |
| 153 | } |
| 154 | |
| 155 | template <typename SType> |
| 156 | static inline Vector2<SType> Sqr(const Vector2<SType> &dat) { |
| 157 | return dat.MulComponents(dat); |
| 158 | } |
| 159 | |
| 160 | template <typename SType> |
| 161 | static inline Vector3<SType> Sqr(const Vector3<SType> &dat) { |
| 162 | return dat.MulComponents(dat); |
| 163 | } |
| 164 | |
| 165 | template <typename SType> |
| 166 | static inline Vector4<SType> Sqr(const Vector4<SType> &dat) { |
| 167 | return dat.MulComponents(dat); |
| 168 | } |
| 169 | |
| 170 | // Template function used to take the square root of a number. |
| 171 | // For a vector we square all components |
| 172 | template <typename SType> |
| 173 | static inline SType Sqrt(const SType &dat) { |
| 174 | // Avoid NaN due to imprecision in the calculations |
| 175 | if (dat < 0) return 0; |
| 176 | return sqrt(dat); |
| 177 | } |
| 178 | |
| 179 | template <typename SType> |
| 180 | static inline Vector2<SType> Sqrt(const Vector2<SType> &dat) { |
| 181 | // Avoid NaN due to imprecision in the calculations |
| 182 | return Max(dat, Vector2<SType>()).Sqrt(); |
| 183 | } |
| 184 | |
| 185 | template <typename SType> |
| 186 | static inline Vector3<SType> Sqrt(const Vector3<SType> &dat) { |
| 187 | // Avoid NaN due to imprecision in the calculations |
| 188 | return Max(dat, Vector3<SType>()).Sqrt(); |
| 189 | } |
| 190 | |
| 191 | template <typename SType> |
| 192 | static inline Vector4<SType> Sqrt(const Vector4<SType> &dat) { |
| 193 | // Avoid NaN due to imprecision in the calculations |
| 194 | return Max(dat, Vector4<SType>()).Sqrt(); |
| 195 | } |
| 196 | }; |
| 197 | |
| 198 | // Useful printing function |
| 199 | template <typename VType, typename NumType> |
| 200 | std::ostream &operator<<(std::ostream &out, const Stat1<VType, NumType> &s) { |
| 201 | out << "{ avg = " << s.Mean() << " std = " << s.StdDev() |
| 202 | << " nsamples = " << s.NumSamples() << "}"; |
| 203 | return out; |
| 204 | } |
| 205 | |
| 206 | // Stat1MinMax: same as Stat1, but it also |
| 207 | // keeps the Min and Max values; the "-" |
| 208 | // operator is disabled because it cannot be implemented |
| 209 | // efficiently |
| 210 | template <typename VType, typename NumType> |
| 211 | class Stat1MinMax : public Stat1<VType, NumType> { |
| 212 | public: |
| 213 | typedef Stat1MinMax<VType, NumType> Self; |
| 214 | |
| 215 | Stat1MinMax() { Clear(); } |
| 216 | // Create a sample of value dat and weight 1 |
| 217 | explicit Stat1MinMax(const VType &dat) : Stat1<VType, NumType>(dat) { |
| 218 | max_ = dat; |
| 219 | min_ = dat; |
| 220 | } |
| 221 | // Create statistics for all the samples between begin (included) |
| 222 | // and end(excluded) |
| 223 | explicit Stat1MinMax(const VType *begin, const VType *end) { |
| 224 | Clear(); |
| 225 | for (const VType *item = begin; item < end; ++item) { |
| 226 | (*this) += Stat1MinMax(*item); |
| 227 | } |
| 228 | } |
| 229 | // Create a sample of value dat and weight w |
| 230 | Stat1MinMax(const VType &dat, const NumType &w) |
| 231 | : Stat1<VType, NumType>(dat, w) { |
| 232 | max_ = dat; |
| 233 | min_ = dat; |
| 234 | } |
| 235 | // Copy operator |
| 236 | Stat1MinMax(const Self &stat) : Stat1<VType, NumType>(stat) { |
| 237 | max_ = stat.max_; |
| 238 | min_ = stat.min_; |
| 239 | } |
| 240 | |
| 241 | void Clear() { |
| 242 | Stat1<VType, NumType>::Clear(); |
| 243 | if (std::numeric_limits<VType>::has_infinity) { |
| 244 | min_ = std::numeric_limits<VType>::infinity(); |
| 245 | max_ = -std::numeric_limits<VType>::infinity(); |
| 246 | } else { |
| 247 | min_ = std::numeric_limits<VType>::max(); |
| 248 | max_ = std::numeric_limits<VType>::min(); |
| 249 | } |
| 250 | } |
| 251 | |
| 252 | Self &operator=(const Self &stat) { |
| 253 | this->Stat1<VType, NumType>::operator=(stat); |
| 254 | max_ = stat.max_; |
| 255 | min_ = stat.min_; |
| 256 | return (*this); |
| 257 | } |
| 258 | // Merge statistics from two sample sets. |
| 259 | Self &operator+=(const Self &stat) { |
| 260 | this->Stat1<VType, NumType>::operator+=(stat); |
| 261 | if (stat.max_ > max_) max_ = stat.max_; |
| 262 | if (stat.min_ < min_) min_ = stat.min_; |
| 263 | return (*this); |
| 264 | } |
| 265 | // Multiply the weight of the set of samples by a factor k |
| 266 | Self &operator*=(const VType &stat) { |
| 267 | this->Stat1<VType, NumType>::operator*=(stat); |
| 268 | return (*this); |
| 269 | } |
| 270 | // Merge statistics from two sample sets. |
| 271 | Self operator+(const Self &stat) const { return Self(*this) += stat; } |
| 272 | // Multiply the weight of the set of samples by a factor k |
| 273 | Self operator*(const VType &k) const { return Self(*this) *= k; } |
| 274 | |
| 275 | // Return the maximal value in this sample set |
| 276 | VType Max() const { return max_; } |
| 277 | // Return the minimal value in this sample set |
| 278 | VType Min() const { return min_; } |
| 279 | |
| 280 | private: |
| 281 | // The - operation makes no sense with Min/Max |
| 282 | // unless we keep the full list of values (but we don't) |
| 283 | // make it private, and let it undefined so nobody can call it |
| 284 | Self &operator-=(const Self &stat); // senseless. let it undefined. |
| 285 | |
| 286 | // The operation opposite to - |
| 287 | Self operator-(const Self &stat) const; // senseless. let it undefined. |
| 288 | |
| 289 | // Let i be the index of the samples provided (using +=) |
| 290 | // and weight[i],value[i] be the data of sample #i |
| 291 | // then the variables have the following meaning: |
| 292 | VType max_; // max of value[i] |
| 293 | VType min_; // min of value[i] |
| 294 | }; |
| 295 | |
| 296 | // Useful printing function |
| 297 | template <typename VType, typename NumType> |
| 298 | std::ostream &operator<<(std::ostream &out, |
| 299 | const Stat1MinMax<VType, NumType> &s) { |
| 300 | out << "{ avg = " << s.Mean() << " std = " << s.StdDev() |
| 301 | << " nsamples = " << s.NumSamples() << " min = " << s.Min() |
| 302 | << " max = " << s.Max() << "}"; |
| 303 | return out; |
| 304 | } |
| 305 | } // end namespace benchmark |
| 306 | |
| 307 | #endif // BENCHMARK_STAT_H_ |
trunk/3rdparty/benchmark/src/string_util.cc
| r0 | r253077 | |
| 1 | #include "string_util.h" |
| 2 | |
| 3 | #include <cmath> |
| 4 | #include <cstdarg> |
| 5 | #include <array> |
| 6 | #include <memory> |
| 7 | #include <sstream> |
| 8 | #include <stdio.h> |
| 9 | |
| 10 | #include "arraysize.h" |
| 11 | |
| 12 | namespace benchmark { |
| 13 | namespace { |
| 14 | |
| 15 | // kilo, Mega, Giga, Tera, Peta, Exa, Zetta, Yotta. |
| 16 | const char kBigSIUnits[] = "kMGTPEZY"; |
| 17 | // Kibi, Mebi, Gibi, Tebi, Pebi, Exbi, Zebi, Yobi. |
| 18 | const char kBigIECUnits[] = "KMGTPEZY"; |
| 19 | // milli, micro, nano, pico, femto, atto, zepto, yocto. |
| 20 | const char kSmallSIUnits[] = "munpfazy"; |
| 21 | |
| 22 | // We require that all three arrays have the same size. |
| 23 | static_assert(arraysize(kBigSIUnits) == arraysize(kBigIECUnits), |
| 24 | "SI and IEC unit arrays must be the same size"); |
| 25 | static_assert(arraysize(kSmallSIUnits) == arraysize(kBigSIUnits), |
| 26 | "Small SI and Big SI unit arrays must be the same size"); |
| 27 | |
| 28 | static const int64_t kUnitsSize = arraysize(kBigSIUnits); |
| 29 | |
| 30 | } // end anonymous namespace |
| 31 | |
| 32 | void ToExponentAndMantissa(double val, double thresh, int precision, |
| 33 | double one_k, std::string* mantissa, |
| 34 | int64_t* exponent) { |
| 35 | std::stringstream mantissa_stream; |
| 36 | |
| 37 | if (val < 0) { |
| 38 | mantissa_stream << "-"; |
| 39 | val = -val; |
| 40 | } |
| 41 | |
| 42 | // Adjust threshold so that it never excludes things which can't be rendered |
| 43 | // in 'precision' digits. |
| 44 | const double adjusted_threshold = |
| 45 | std::max(thresh, 1.0 / std::pow(10.0, precision)); |
| 46 | const double big_threshold = adjusted_threshold * one_k; |
| 47 | const double small_threshold = adjusted_threshold; |
| 48 | |
| 49 | if (val > big_threshold) { |
| 50 | // Positive powers |
| 51 | double scaled = val; |
| 52 | for (size_t i = 0; i < arraysize(kBigSIUnits); ++i) { |
| 53 | scaled /= one_k; |
| 54 | if (scaled <= big_threshold) { |
| 55 | mantissa_stream << scaled; |
| 56 | *exponent = i + 1; |
| 57 | *mantissa = mantissa_stream.str(); |
| 58 | return; |
| 59 | } |
| 60 | } |
| 61 | mantissa_stream << val; |
| 62 | *exponent = 0; |
| 63 | } else if (val < small_threshold) { |
| 64 | // Negative powers |
| 65 | double scaled = val; |
| 66 | for (size_t i = 0; i < arraysize(kSmallSIUnits); ++i) { |
| 67 | scaled *= one_k; |
| 68 | if (scaled >= small_threshold) { |
| 69 | mantissa_stream << scaled; |
| 70 | *exponent = -static_cast<int64_t>(i + 1); |
| 71 | *mantissa = mantissa_stream.str(); |
| 72 | return; |
| 73 | } |
| 74 | } |
| 75 | mantissa_stream << val; |
| 76 | *exponent = 0; |
| 77 | } else { |
| 78 | mantissa_stream << val; |
| 79 | *exponent = 0; |
| 80 | } |
| 81 | *mantissa = mantissa_stream.str(); |
| 82 | } |
| 83 | |
| 84 | std::string ExponentToPrefix(int64_t exponent, bool iec) { |
| 85 | if (exponent == 0) return ""; |
| 86 | |
| 87 | const int64_t index = (exponent > 0 ? exponent - 1 : -exponent - 1); |
| 88 | if (index >= kUnitsSize) return ""; |
| 89 | |
| 90 | const char* array = |
| 91 | (exponent > 0 ? (iec ? kBigIECUnits : kBigSIUnits) : kSmallSIUnits); |
| 92 | if (iec) |
| 93 | return array[index] + std::string("i"); |
| 94 | else |
| 95 | return std::string(1, array[index]); |
| 96 | } |
| 97 | |
| 98 | std::string ToBinaryStringFullySpecified(double value, double threshold, |
| 99 | int precision) { |
| 100 | std::string mantissa; |
| 101 | int64_t exponent; |
| 102 | ToExponentAndMantissa(value, threshold, precision, 1024.0, &mantissa, |
| 103 | &exponent); |
| 104 | return mantissa + ExponentToPrefix(exponent, false); |
| 105 | } |
| 106 | |
| 107 | void AppendHumanReadable(int n, std::string* str) { |
| 108 | std::stringstream ss; |
| 109 | // Round down to the nearest SI prefix. |
| 110 | ss << "/" << ToBinaryStringFullySpecified(n, 1.0, 0); |
| 111 | *str += ss.str(); |
| 112 | } |
| 113 | |
| 114 | std::string HumanReadableNumber(double n) { |
| 115 | // 1.1 means that figures up to 1.1k should be shown with the next unit down; |
| 116 | // this softens edge effects. |
| 117 | // 1 means that we should show one decimal place of precision. |
| 118 | return ToBinaryStringFullySpecified(n, 1.1, 1); |
| 119 | } |
| 120 | |
| 121 | std::string StringPrintFImp(const char *msg, va_list args) |
| 122 | { |
| 123 | // we might need a second shot at this, so pre-emptivly make a copy |
| 124 | va_list args_cp; |
| 125 | va_copy(args_cp, args); |
| 126 | |
| 127 | // TODO(ericwf): use std::array for first attempt to avoid one memory |
| 128 | // allocation guess what the size might be |
| 129 | std::array<char, 256> local_buff; |
| 130 | std::size_t size = local_buff.size(); |
| 131 | // 2015-10-08: vsnprintf is used instead of snd::vsnprintf due to a limitation in the android-ndk |
| 132 | auto ret = vsnprintf(local_buff.data(), size, msg, args_cp); |
| 133 | |
| 134 | va_end(args_cp); |
| 135 | |
| 136 | // handle empty expansion |
| 137 | if (ret == 0) |
| 138 | return std::string{}; |
| 139 | if (static_cast<std::size_t>(ret) < size) |
| 140 | return std::string(local_buff.data()); |
| 141 | |
| 142 | // we did not provide a long enough buffer on our first attempt. |
| 143 | // add 1 to size to account for null-byte in size cast to prevent overflow |
| 144 | size = static_cast<std::size_t>(ret) + 1; |
| 145 | auto buff_ptr = std::unique_ptr<char[]>(new char[size]); |
| 146 | // 2015-10-08: vsnprintf is used instead of snd::vsnprintf due to a limitation in the android-ndk |
| 147 | ret = vsnprintf(buff_ptr.get(), size, msg, args); |
| 148 | return std::string(buff_ptr.get()); |
| 149 | } |
| 150 | |
| 151 | std::string StringPrintF(const char* format, ...) |
| 152 | { |
| 153 | va_list args; |
| 154 | va_start(args, format); |
| 155 | std::string tmp = StringPrintFImp(format, args); |
| 156 | va_end(args); |
| 157 | return tmp; |
| 158 | } |
| 159 | |
| 160 | void ReplaceAll(std::string* str, const std::string& from, |
| 161 | const std::string& to) { |
| 162 | std::size_t start = 0; |
| 163 | while((start = str->find(from, start)) != std::string::npos) { |
| 164 | str->replace(start, from.length(), to); |
| 165 | start += to.length(); |
| 166 | } |
| 167 | } |
| 168 | |
| 169 | } // end namespace benchmark |
trunk/3rdparty/benchmark/src/sysinfo.cc
| r0 | r253077 | |
| 1 | // Copyright 2015 Google Inc. All rights reserved. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | #include "sysinfo.h" |
| 16 | #include "internal_macros.h" |
| 17 | |
| 18 | #ifdef BENCHMARK_OS_WINDOWS |
| 19 | #include <Shlwapi.h> |
| 20 | #include <Windows.h> |
| 21 | #include <VersionHelpers.h> |
| 22 | #else |
| 23 | #include <fcntl.h> |
| 24 | #include <sys/resource.h> |
| 25 | #include <sys/types.h> // this header must be included before 'sys/sysctl.h' to avoid compilation error on FreeBSD |
| 26 | #include <sys/time.h> |
| 27 | #include <unistd.h> |
| 28 | #if defined BENCHMARK_OS_FREEBSD || defined BENCHMARK_OS_MACOSX |
| 29 | #include <sys/sysctl.h> |
| 30 | #endif |
| 31 | #endif |
| 32 | |
| 33 | #include <cerrno> |
| 34 | #include <cstdio> |
| 35 | #include <cstdint> |
| 36 | #include <cstdlib> |
| 37 | #include <cstring> |
| 38 | #include <iostream> |
| 39 | #include <limits> |
| 40 | #include <mutex> |
| 41 | |
| 42 | #include "arraysize.h" |
| 43 | #include "check.h" |
| 44 | #include "cycleclock.h" |
| 45 | #include "internal_macros.h" |
| 46 | #include "log.h" |
| 47 | #include "sleep.h" |
| 48 | #include "string_util.h" |
| 49 | |
| 50 | namespace benchmark { |
| 51 | namespace { |
| 52 | std::once_flag cpuinfo_init; |
| 53 | double cpuinfo_cycles_per_second = 1.0; |
| 54 | int cpuinfo_num_cpus = 1; // Conservative guess |
| 55 | std::mutex cputimens_mutex; |
| 56 | |
| 57 | #if !defined BENCHMARK_OS_MACOSX |
| 58 | const int64_t estimate_time_ms = 1000; |
| 59 | |
| 60 | // Helper function estimates cycles/sec by observing cycles elapsed during |
| 61 | // sleep(). Using small sleep time decreases accuracy significantly. |
| 62 | int64_t EstimateCyclesPerSecond() { |
| 63 | const int64_t start_ticks = cycleclock::Now(); |
| 64 | SleepForMilliseconds(estimate_time_ms); |
| 65 | return cycleclock::Now() - start_ticks; |
| 66 | } |
| 67 | #endif |
| 68 | |
| 69 | #if defined BENCHMARK_OS_LINUX || defined BENCHMARK_OS_CYGWIN |
| 70 | // Helper function for reading an int from a file. Returns true if successful |
| 71 | // and the memory location pointed to by value is set to the value read. |
| 72 | bool ReadIntFromFile(const char* file, long* value) { |
| 73 | bool ret = false; |
| 74 | int fd = open(file, O_RDONLY); |
| 75 | if (fd != -1) { |
| 76 | char line[1024]; |
| 77 | char* err; |
| 78 | memset(line, '\0', sizeof(line)); |
| 79 | CHECK(read(fd, line, sizeof(line) - 1)); |
| 80 | const long temp_value = strtol(line, &err, 10); |
| 81 | if (line[0] != '\0' && (*err == '\n' || *err == '\0')) { |
| 82 | *value = temp_value; |
| 83 | ret = true; |
| 84 | } |
| 85 | close(fd); |
| 86 | } |
| 87 | return ret; |
| 88 | } |
| 89 | #endif |
| 90 | |
| 91 | void InitializeSystemInfo() { |
| 92 | #if defined BENCHMARK_OS_LINUX || defined BENCHMARK_OS_CYGWIN |
| 93 | char line[1024]; |
| 94 | char* err; |
| 95 | long freq; |
| 96 | |
| 97 | bool saw_mhz = false; |
| 98 | |
| 99 | // If the kernel is exporting the tsc frequency use that. There are issues |
| 100 | // where cpuinfo_max_freq cannot be relied on because the BIOS may be |
| 101 | // exporintg an invalid p-state (on x86) or p-states may be used to put the |
| 102 | // processor in a new mode (turbo mode). Essentially, those frequencies |
| 103 | // cannot always be relied upon. The same reasons apply to /proc/cpuinfo as |
| 104 | // well. |
| 105 | if (!saw_mhz && |
| 106 | ReadIntFromFile("/sys/devices/system/cpu/cpu0/tsc_freq_khz", &freq)) { |
| 107 | // The value is in kHz (as the file name suggests). For example, on a |
| 108 | // 2GHz warpstation, the file contains the value "2000000". |
| 109 | cpuinfo_cycles_per_second = freq * 1000.0; |
| 110 | saw_mhz = true; |
| 111 | } |
| 112 | |
| 113 | // If CPU scaling is in effect, we want to use the *maximum* frequency, |
| 114 | // not whatever CPU speed some random processor happens to be using now. |
| 115 | if (!saw_mhz && |
| 116 | ReadIntFromFile("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", |
| 117 | &freq)) { |
| 118 | // The value is in kHz. For example, on a 2GHz warpstation, the file |
| 119 | // contains the value "2000000". |
| 120 | cpuinfo_cycles_per_second = freq * 1000.0; |
| 121 | saw_mhz = true; |
| 122 | } |
| 123 | |
| 124 | // Read /proc/cpuinfo for other values, and if there is no cpuinfo_max_freq. |
| 125 | const char* pname = "/proc/cpuinfo"; |
| 126 | int fd = open(pname, O_RDONLY); |
| 127 | if (fd == -1) { |
| 128 | perror(pname); |
| 129 | if (!saw_mhz) { |
| 130 | cpuinfo_cycles_per_second = static_cast<double>(EstimateCyclesPerSecond()); |
| 131 | } |
| 132 | return; |
| 133 | } |
| 134 | |
| 135 | double bogo_clock = 1.0; |
| 136 | bool saw_bogo = false; |
| 137 | long max_cpu_id = 0; |
| 138 | int num_cpus = 0; |
| 139 | line[0] = line[1] = '\0'; |
| 140 | size_t chars_read = 0; |
| 141 | do { // we'll exit when the last read didn't read anything |
| 142 | // Move the next line to the beginning of the buffer |
| 143 | const size_t oldlinelen = strlen(line); |
| 144 | if (sizeof(line) == oldlinelen + 1) // oldlinelen took up entire line |
| 145 | line[0] = '\0'; |
| 146 | else // still other lines left to save |
| 147 | memmove(line, line + oldlinelen + 1, sizeof(line) - (oldlinelen + 1)); |
| 148 | // Terminate the new line, reading more if we can't find the newline |
| 149 | char* newline = strchr(line, '\n'); |
| 150 | if (newline == nullptr) { |
| 151 | const size_t linelen = strlen(line); |
| 152 | const size_t bytes_to_read = sizeof(line) - 1 - linelen; |
| 153 | CHECK(bytes_to_read > 0); // because the memmove recovered >=1 bytes |
| 154 | chars_read = read(fd, line + linelen, bytes_to_read); |
| 155 | line[linelen + chars_read] = '\0'; |
| 156 | newline = strchr(line, '\n'); |
| 157 | } |
| 158 | if (newline != nullptr) *newline = '\0'; |
| 159 | |
| 160 | // When parsing the "cpu MHz" and "bogomips" (fallback) entries, we only |
| 161 | // accept postive values. Some environments (virtual machines) report zero, |
| 162 | // which would cause infinite looping in WallTime_Init. |
| 163 | if (!saw_mhz && strncasecmp(line, "cpu MHz", sizeof("cpu MHz") - 1) == 0) { |
| 164 | const char* freqstr = strchr(line, ':'); |
| 165 | if (freqstr) { |
| 166 | cpuinfo_cycles_per_second = strtod(freqstr + 1, &err) * 1000000.0; |
| 167 | if (freqstr[1] != '\0' && *err == '\0' && cpuinfo_cycles_per_second > 0) |
| 168 | saw_mhz = true; |
| 169 | } |
| 170 | } else if (strncasecmp(line, "bogomips", sizeof("bogomips") - 1) == 0) { |
| 171 | const char* freqstr = strchr(line, ':'); |
| 172 | if (freqstr) { |
| 173 | bogo_clock = strtod(freqstr + 1, &err) * 1000000.0; |
| 174 | if (freqstr[1] != '\0' && *err == '\0' && bogo_clock > 0) |
| 175 | saw_bogo = true; |
| 176 | } |
| 177 | } else if (strncasecmp(line, "processor", sizeof("processor") - 1) == 0) { |
| 178 | num_cpus++; // count up every time we see an "processor :" entry |
| 179 | const char* freqstr = strchr(line, ':'); |
| 180 | if (freqstr) { |
| 181 | const long cpu_id = strtol(freqstr + 1, &err, 10); |
| 182 | if (freqstr[1] != '\0' && *err == '\0' && max_cpu_id < cpu_id) |
| 183 | max_cpu_id = cpu_id; |
| 184 | } |
| 185 | } |
| 186 | } while (chars_read > 0); |
| 187 | close(fd); |
| 188 | |
| 189 | if (!saw_mhz) { |
| 190 | if (saw_bogo) { |
| 191 | // If we didn't find anything better, we'll use bogomips, but |
| 192 | // we're not happy about it. |
| 193 | cpuinfo_cycles_per_second = bogo_clock; |
| 194 | } else { |
| 195 | // If we don't even have bogomips, we'll use the slow estimation. |
| 196 | cpuinfo_cycles_per_second = static_cast<double>(EstimateCyclesPerSecond()); |
| 197 | } |
| 198 | } |
| 199 | if (num_cpus == 0) { |
| 200 | fprintf(stderr, "Failed to read num. CPUs correctly from /proc/cpuinfo\n"); |
| 201 | } else { |
| 202 | if ((max_cpu_id + 1) != num_cpus) { |
| 203 | fprintf(stderr, |
| 204 | "CPU ID assignments in /proc/cpuinfo seems messed up." |
| 205 | " This is usually caused by a bad BIOS.\n"); |
| 206 | } |
| 207 | cpuinfo_num_cpus = num_cpus; |
| 208 | } |
| 209 | |
| 210 | #elif defined BENCHMARK_OS_FREEBSD |
| 211 | // For this sysctl to work, the machine must be configured without |
| 212 | // SMP, APIC, or APM support. hz should be 64-bit in freebsd 7.0 |
| 213 | // and later. Before that, it's a 32-bit quantity (and gives the |
| 214 | // wrong answer on machines faster than 2^32 Hz). See |
| 215 | // http://lists.freebsd.org/pipermail/freebsd-i386/2004-November/001846.html |
| 216 | // But also compare FreeBSD 7.0: |
| 217 | // http://fxr.watson.org/fxr/source/i386/i386/tsc.c?v=RELENG70#L223 |
| 218 | // 231 error = sysctl_handle_quad(oidp, &freq, 0, req); |
| 219 | // To FreeBSD 6.3 (it's the same in 6-STABLE): |
| 220 | // http://fxr.watson.org/fxr/source/i386/i386/tsc.c?v=RELENG6#L131 |
| 221 | // 139 error = sysctl_handle_int(oidp, &freq, sizeof(freq), req); |
| 222 | #if __FreeBSD__ >= 7 |
| 223 | uint64_t hz = 0; |
| 224 | #else |
| 225 | unsigned int hz = 0; |
| 226 | #endif |
| 227 | size_t sz = sizeof(hz); |
| 228 | const char* sysctl_path = "machdep.tsc_freq"; |
| 229 | if (sysctlbyname(sysctl_path, &hz, &sz, nullptr, 0) != 0) { |
| 230 | fprintf(stderr, "Unable to determine clock rate from sysctl: %s: %s\n", |
| 231 | sysctl_path, strerror(errno)); |
| 232 | cpuinfo_cycles_per_second = static_cast<double>(EstimateCyclesPerSecond()); |
| 233 | } else { |
| 234 | cpuinfo_cycles_per_second = hz; |
| 235 | } |
| 236 | // TODO: also figure out cpuinfo_num_cpus |
| 237 | |
| 238 | #elif defined BENCHMARK_OS_WINDOWS |
| 239 | // In NT, read MHz from the registry. If we fail to do so or we're in win9x |
| 240 | // then make a crude estimate. |
| 241 | DWORD data, data_size = sizeof(data); |
| 242 | if (IsWindowsXPOrGreater() && |
| 243 | SUCCEEDED( |
| 244 | SHGetValueA(HKEY_LOCAL_MACHINE, |
| 245 | "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", |
| 246 | "~MHz", nullptr, &data, &data_size))) |
| 247 | cpuinfo_cycles_per_second = static_cast<double>((int64_t)data * (int64_t)(1000 * 1000)); // was mhz |
| 248 | else |
| 249 | cpuinfo_cycles_per_second = static_cast<double>(EstimateCyclesPerSecond()); |
| 250 | // TODO: also figure out cpuinfo_num_cpus |
| 251 | |
| 252 | #elif defined BENCHMARK_OS_MACOSX |
| 253 | // returning "mach time units" per second. the current number of elapsed |
| 254 | // mach time units can be found by calling uint64 mach_absolute_time(); |
| 255 | // while not as precise as actual CPU cycles, it is accurate in the face |
| 256 | // of CPU frequency scaling and multi-cpu/core machines. |
| 257 | // Our mac users have these types of machines, and accuracy |
| 258 | // (i.e. correctness) trumps precision. |
| 259 | // See cycleclock.h: CycleClock::Now(), which returns number of mach time |
| 260 | // units on Mac OS X. |
| 261 | mach_timebase_info_data_t timebase_info; |
| 262 | mach_timebase_info(&timebase_info); |
| 263 | double mach_time_units_per_nanosecond = |
| 264 | static_cast<double>(timebase_info.denom) / |
| 265 | static_cast<double>(timebase_info.numer); |
| 266 | cpuinfo_cycles_per_second = mach_time_units_per_nanosecond * 1e9; |
| 267 | |
| 268 | int num_cpus = 0; |
| 269 | size_t size = sizeof(num_cpus); |
| 270 | int numcpus_name[] = {CTL_HW, HW_NCPU}; |
| 271 | if (::sysctl(numcpus_name, arraysize(numcpus_name), &num_cpus, &size, nullptr, 0) == |
| 272 | 0 && |
| 273 | (size == sizeof(num_cpus))) |
| 274 | cpuinfo_num_cpus = num_cpus; |
| 275 | |
| 276 | #else |
| 277 | // Generic cycles per second counter |
| 278 | cpuinfo_cycles_per_second = static_cast<double>(EstimateCyclesPerSecond()); |
| 279 | #endif |
| 280 | } |
| 281 | } // end namespace |
| 282 | |
| 283 | // getrusage() based implementation of MyCPUUsage |
| 284 | static double MyCPUUsageRUsage() { |
| 285 | #ifndef BENCHMARK_OS_WINDOWS |
| 286 | struct rusage ru; |
| 287 | if (getrusage(RUSAGE_SELF, &ru) == 0) { |
| 288 | return (static_cast<double>(ru.ru_utime.tv_sec) + |
| 289 | static_cast<double>(ru.ru_utime.tv_usec) * 1e-6 + |
| 290 | static_cast<double>(ru.ru_stime.tv_sec) + |
| 291 | static_cast<double>(ru.ru_stime.tv_usec) * 1e-6); |
| 292 | } else { |
| 293 | return 0.0; |
| 294 | } |
| 295 | #else |
| 296 | HANDLE proc = GetCurrentProcess(); |
| 297 | FILETIME creation_time; |
| 298 | FILETIME exit_time; |
| 299 | FILETIME kernel_time; |
| 300 | FILETIME user_time; |
| 301 | ULARGE_INTEGER kernel; |
| 302 | ULARGE_INTEGER user; |
| 303 | GetProcessTimes(proc, &creation_time, &exit_time, &kernel_time, &user_time); |
| 304 | kernel.HighPart = kernel_time.dwHighDateTime; |
| 305 | kernel.LowPart = kernel_time.dwLowDateTime; |
| 306 | user.HighPart = user_time.dwHighDateTime; |
| 307 | user.LowPart = user_time.dwLowDateTime; |
| 308 | return (static_cast<double>(kernel.QuadPart) + |
| 309 | static_cast<double>(user.QuadPart)) * 1e-7; |
| 310 | #endif // OS_WINDOWS |
| 311 | } |
| 312 | |
| 313 | #ifndef BENCHMARK_OS_WINDOWS |
| 314 | static bool MyCPUUsageCPUTimeNsLocked(double* cputime) { |
| 315 | static int cputime_fd = -1; |
| 316 | if (cputime_fd == -1) { |
| 317 | cputime_fd = open("/proc/self/cputime_ns", O_RDONLY); |
| 318 | if (cputime_fd < 0) { |
| 319 | cputime_fd = -1; |
| 320 | return false; |
| 321 | } |
| 322 | } |
| 323 | char buff[64]; |
| 324 | memset(buff, 0, sizeof(buff)); |
| 325 | if (pread(cputime_fd, buff, sizeof(buff) - 1, 0) <= 0) { |
| 326 | close(cputime_fd); |
| 327 | cputime_fd = -1; |
| 328 | return false; |
| 329 | } |
| 330 | unsigned long long result = strtoull(buff, nullptr, 0); |
| 331 | if (result == (std::numeric_limits<unsigned long long>::max)()) { |
| 332 | close(cputime_fd); |
| 333 | cputime_fd = -1; |
| 334 | return false; |
| 335 | } |
| 336 | *cputime = static_cast<double>(result) / 1e9; |
| 337 | return true; |
| 338 | } |
| 339 | #endif // OS_WINDOWS |
| 340 | |
| 341 | double MyCPUUsage() { |
| 342 | #ifndef BENCHMARK_OS_WINDOWS |
| 343 | { |
| 344 | std::lock_guard<std::mutex> l(cputimens_mutex); |
| 345 | static bool use_cputime_ns = true; |
| 346 | if (use_cputime_ns) { |
| 347 | double value; |
| 348 | if (MyCPUUsageCPUTimeNsLocked(&value)) { |
| 349 | return value; |
| 350 | } |
| 351 | // Once MyCPUUsageCPUTimeNsLocked fails once fall back to getrusage(). |
| 352 | VLOG(1) << "Reading /proc/self/cputime_ns failed. Using getrusage().\n"; |
| 353 | use_cputime_ns = false; |
| 354 | } |
| 355 | } |
| 356 | #endif // OS_WINDOWS |
| 357 | return MyCPUUsageRUsage(); |
| 358 | } |
| 359 | |
| 360 | double ChildrenCPUUsage() { |
| 361 | #ifndef BENCHMARK_OS_WINDOWS |
| 362 | struct rusage ru; |
| 363 | if (getrusage(RUSAGE_CHILDREN, &ru) == 0) { |
| 364 | return (static_cast<double>(ru.ru_utime.tv_sec) + |
| 365 | static_cast<double>(ru.ru_utime.tv_usec) * 1e-6 + |
| 366 | static_cast<double>(ru.ru_stime.tv_sec) + |
| 367 | static_cast<double>(ru.ru_stime.tv_usec) * 1e-6); |
| 368 | } else { |
| 369 | return 0.0; |
| 370 | } |
| 371 | #else |
| 372 | // TODO: Not sure what this even means on Windows |
| 373 | return 0.0; |
| 374 | #endif // OS_WINDOWS |
| 375 | } |
| 376 | |
| 377 | double CyclesPerSecond(void) { |
| 378 | std::call_once(cpuinfo_init, InitializeSystemInfo); |
| 379 | return cpuinfo_cycles_per_second; |
| 380 | } |
| 381 | |
| 382 | int NumCPUs(void) { |
| 383 | std::call_once(cpuinfo_init, InitializeSystemInfo); |
| 384 | return cpuinfo_num_cpus; |
| 385 | } |
| 386 | |
| 387 | // The ""'s catch people who don't pass in a literal for "str" |
| 388 | #define strliterallen(str) (sizeof("" str "") - 1) |
| 389 | |
| 390 | // Must use a string literal for prefix. |
| 391 | #define memprefix(str, len, prefix) \ |
| 392 | ((((len) >= strliterallen(prefix)) && \ |
| 393 | std::memcmp(str, prefix, strliterallen(prefix)) == 0) \ |
| 394 | ? str + strliterallen(prefix) \ |
| 395 | : nullptr) |
| 396 | |
| 397 | bool CpuScalingEnabled() { |
| 398 | #ifndef BENCHMARK_OS_WINDOWS |
| 399 | // On Linux, the CPUfreq subsystem exposes CPU information as files on the |
| 400 | // local file system. If reading the exported files fails, then we may not be |
| 401 | // running on Linux, so we silently ignore all the read errors. |
| 402 | for (int cpu = 0, num_cpus = NumCPUs(); cpu < num_cpus; ++cpu) { |
| 403 | std::string governor_file = StrCat("/sys/devices/system/cpu/cpu", cpu, |
| 404 | "/cpufreq/scaling_governor"); |
| 405 | FILE* file = fopen(governor_file.c_str(), "r"); |
| 406 | if (!file) break; |
| 407 | char buff[16]; |
| 408 | size_t bytes_read = fread(buff, 1, sizeof(buff), file); |
| 409 | fclose(file); |
| 410 | if (memprefix(buff, bytes_read, "performance") == nullptr) return true; |
| 411 | } |
| 412 | #endif |
| 413 | return false; |
| 414 | } |
| 415 | |
| 416 | } // end namespace benchmark |
trunk/3rdparty/benchmark/src/walltime.cc
| r0 | r253077 | |
| 1 | // Copyright 2015 Google Inc. All rights reserved. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | #include "benchmark/macros.h" |
| 16 | #include "internal_macros.h" |
| 17 | #include "walltime.h" |
| 18 | |
| 19 | #if defined(BENCHMARK_OS_WINDOWS) |
| 20 | #include <time.h> |
| 21 | #include <winsock.h> // for timeval |
| 22 | #else |
| 23 | #include <sys/time.h> |
| 24 | #endif |
| 25 | |
| 26 | #include <cstdio> |
| 27 | #include <cstdint> |
| 28 | #include <cstring> |
| 29 | #include <ctime> |
| 30 | |
| 31 | #include <atomic> |
| 32 | #include <chrono> |
| 33 | #include <limits> |
| 34 | |
| 35 | #include "arraysize.h" |
| 36 | #include "check.h" |
| 37 | #include "cycleclock.h" |
| 38 | #include "log.h" |
| 39 | #include "sysinfo.h" |
| 40 | |
| 41 | namespace benchmark { |
| 42 | namespace walltime { |
| 43 | |
| 44 | namespace { |
| 45 | |
| 46 | #if defined(HAVE_STEADY_CLOCK) |
| 47 | template <bool HighResIsSteady = std::chrono::high_resolution_clock::is_steady> |
| 48 | struct ChooseSteadyClock { |
| 49 | typedef std::chrono::high_resolution_clock type; |
| 50 | }; |
| 51 | |
| 52 | template <> |
| 53 | struct ChooseSteadyClock<false> { |
| 54 | typedef std::chrono::steady_clock type; |
| 55 | }; |
| 56 | #endif |
| 57 | |
| 58 | struct ChooseClockType { |
| 59 | #if defined(HAVE_STEADY_CLOCK) |
| 60 | typedef ChooseSteadyClock<>::type type; |
| 61 | #else |
| 62 | typedef std::chrono::high_resolution_clock type; |
| 63 | #endif |
| 64 | }; |
| 65 | |
| 66 | class WallTimeImp |
| 67 | { |
| 68 | public: |
| 69 | WallTime Now(); |
| 70 | |
| 71 | static WallTimeImp& GetWallTimeImp() { |
| 72 | static WallTimeImp* imp = new WallTimeImp(); |
| 73 | return *imp; |
| 74 | } |
| 75 | |
| 76 | private: |
| 77 | WallTimeImp(); |
| 78 | // Helper routines to load/store a float from an AtomicWord. Required because |
| 79 | // g++ < 4.7 doesn't support std::atomic<float> correctly. I cannot wait to |
| 80 | // get rid of this horror show. |
| 81 | void SetDrift(float f) { |
| 82 | int32_t w; |
| 83 | memcpy(&w, &f, sizeof(f)); |
| 84 | std::atomic_store(&drift_adjust_, w); |
| 85 | } |
| 86 | |
| 87 | float GetDrift() const { |
| 88 | float f; |
| 89 | int32_t w = std::atomic_load(&drift_adjust_); |
| 90 | memcpy(&f, &w, sizeof(f)); |
| 91 | return f; |
| 92 | } |
| 93 | |
| 94 | WallTime Slow() const { |
| 95 | struct timeval tv; |
| 96 | #if defined(BENCHMARK_OS_WINDOWS) |
| 97 | FILETIME file_time; |
| 98 | SYSTEMTIME system_time; |
| 99 | ULARGE_INTEGER ularge; |
| 100 | const unsigned __int64 epoch = 116444736000000000LL; |
| 101 | |
| 102 | GetSystemTime(&system_time); |
| 103 | SystemTimeToFileTime(&system_time, &file_time); |
| 104 | ularge.LowPart = file_time.dwLowDateTime; |
| 105 | ularge.HighPart = file_time.dwHighDateTime; |
| 106 | |
| 107 | tv.tv_sec = (long)((ularge.QuadPart - epoch) / (10L * 1000 * 1000)); |
| 108 | tv.tv_usec = (long)(system_time.wMilliseconds * 1000); |
| 109 | #else |
| 110 | gettimeofday(&tv, nullptr); |
| 111 | #endif |
| 112 | return tv.tv_sec + tv.tv_usec * 1e-6; |
| 113 | } |
| 114 | |
| 115 | private: |
| 116 | static_assert(sizeof(float) <= sizeof(int32_t), |
| 117 | "type sizes don't allow the drift_adjust hack"); |
| 118 | |
| 119 | WallTime base_walltime_; |
| 120 | int64_t base_cycletime_; |
| 121 | int64_t cycles_per_second_; |
| 122 | double seconds_per_cycle_; |
| 123 | uint32_t last_adjust_time_; |
| 124 | std::atomic<int32_t> drift_adjust_; |
| 125 | int64_t max_interval_cycles_; |
| 126 | |
| 127 | BENCHMARK_DISALLOW_COPY_AND_ASSIGN(WallTimeImp); |
| 128 | }; |
| 129 | |
| 130 | |
| 131 | WallTime WallTimeImp::Now() { |
| 132 | WallTime now = 0.0; |
| 133 | WallTime result = 0.0; |
| 134 | int64_t ct = 0; |
| 135 | uint32_t top_bits = 0; |
| 136 | do { |
| 137 | ct = cycleclock::Now(); |
| 138 | int64_t cycle_delta = ct - base_cycletime_; |
| 139 | result = base_walltime_ + cycle_delta * seconds_per_cycle_; |
| 140 | |
| 141 | top_bits = static_cast<uint32_t>(uint64_t(ct) >> 32); |
| 142 | // Recompute drift no more often than every 2^32 cycles. |
| 143 | // I.e., @2GHz, ~ every two seconds |
| 144 | if (top_bits == last_adjust_time_) { // don't need to recompute drift |
| 145 | return result + GetDrift(); |
| 146 | } |
| 147 | |
| 148 | now = Slow(); |
| 149 | } while (cycleclock::Now() - ct > max_interval_cycles_); |
| 150 | // We are now sure that "now" and "result" were produced within |
| 151 | // kMaxErrorInterval of one another. |
| 152 | |
| 153 | SetDrift(static_cast<float>(now - result)); |
| 154 | last_adjust_time_ = top_bits; |
| 155 | return now; |
| 156 | } |
| 157 | |
| 158 | |
| 159 | WallTimeImp::WallTimeImp() |
| 160 | : base_walltime_(0.0), base_cycletime_(0), |
| 161 | cycles_per_second_(0), seconds_per_cycle_(0.0), |
| 162 | last_adjust_time_(0), drift_adjust_(0), |
| 163 | max_interval_cycles_(0) { |
| 164 | const double kMaxErrorInterval = 100e-6; |
| 165 | cycles_per_second_ = static_cast<int64_t>(CyclesPerSecond()); |
| 166 | CHECK(cycles_per_second_ != 0); |
| 167 | seconds_per_cycle_ = 1.0 / cycles_per_second_; |
| 168 | max_interval_cycles_ = |
| 169 | static_cast<int64_t>(cycles_per_second_ * kMaxErrorInterval); |
| 170 | do { |
| 171 | base_cycletime_ = cycleclock::Now(); |
| 172 | base_walltime_ = Slow(); |
| 173 | } while (cycleclock::Now() - base_cycletime_ > max_interval_cycles_); |
| 174 | // We are now sure that "base_walltime" and "base_cycletime" were produced |
| 175 | // within kMaxErrorInterval of one another. |
| 176 | |
| 177 | SetDrift(0.0); |
| 178 | last_adjust_time_ = static_cast<uint32_t>(uint64_t(base_cycletime_) >> 32); |
| 179 | } |
| 180 | |
| 181 | WallTime CPUWalltimeNow() { |
| 182 | static WallTimeImp& imp = WallTimeImp::GetWallTimeImp(); |
| 183 | return imp.Now(); |
| 184 | } |
| 185 | |
| 186 | WallTime ChronoWalltimeNow() { |
| 187 | typedef ChooseClockType::type Clock; |
| 188 | typedef std::chrono::duration<WallTime, std::chrono::seconds::period> |
| 189 | FPSeconds; |
| 190 | static_assert(std::chrono::treat_as_floating_point<WallTime>::value, |
| 191 | "This type must be treated as a floating point type."); |
| 192 | auto now = Clock::now().time_since_epoch(); |
| 193 | return std::chrono::duration_cast<FPSeconds>(now).count(); |
| 194 | } |
| 195 | |
| 196 | bool UseCpuCycleClock() { |
| 197 | bool useWallTime = !CpuScalingEnabled(); |
| 198 | if (useWallTime) { |
| 199 | VLOG(1) << "Using the CPU cycle clock to provide walltime::Now().\n"; |
| 200 | } else { |
| 201 | VLOG(1) << "Using std::chrono to provide walltime::Now().\n"; |
| 202 | } |
| 203 | return useWallTime; |
| 204 | } |
| 205 | |
| 206 | |
| 207 | } // end anonymous namespace |
| 208 | |
| 209 | // WallTimeImp doesn't work when CPU Scaling is enabled. If CPU Scaling is |
| 210 | // enabled at the start of the program then std::chrono::system_clock is used |
| 211 | // instead. |
| 212 | WallTime Now() |
| 213 | { |
| 214 | static bool useCPUClock = UseCpuCycleClock(); |
| 215 | if (useCPUClock) { |
| 216 | return CPUWalltimeNow(); |
| 217 | } else { |
| 218 | return ChronoWalltimeNow(); |
| 219 | } |
| 220 | } |
| 221 | |
| 222 | } // end namespace walltime |
| 223 | |
| 224 | |
| 225 | namespace { |
| 226 | |
| 227 | std::string DateTimeString(bool local) { |
| 228 | typedef std::chrono::system_clock Clock; |
| 229 | std::time_t now = Clock::to_time_t(Clock::now()); |
| 230 | char storage[128]; |
| 231 | std::size_t written; |
| 232 | |
| 233 | if (local) { |
| 234 | #if defined(BENCHMARK_OS_WINDOWS) |
| 235 | written = std::strftime(storage, sizeof(storage), "%x %X", ::localtime(&now)); |
| 236 | #else |
| 237 | std::tm timeinfo; |
| 238 | std::memset(&timeinfo, 0, sizeof(std::tm)); |
| 239 | ::localtime_r(&now, &timeinfo); |
| 240 | written = std::strftime(storage, sizeof(storage), "%F %T", &timeinfo); |
| 241 | #endif |
| 242 | } else { |
| 243 | #if defined(BENCHMARK_OS_WINDOWS) |
| 244 | written = std::strftime(storage, sizeof(storage), "%x %X", ::gmtime(&now)); |
| 245 | #else |
| 246 | std::tm timeinfo; |
| 247 | std::memset(&timeinfo, 0, sizeof(std::tm)); |
| 248 | ::gmtime_r(&now, &timeinfo); |
| 249 | written = std::strftime(storage, sizeof(storage), "%F %T", &timeinfo); |
| 250 | #endif |
| 251 | } |
| 252 | CHECK(written < arraysize(storage)); |
| 253 | ((void)written); // prevent unused variable in optimized mode. |
| 254 | return std::string(storage); |
| 255 | } |
| 256 | |
| 257 | } // end namespace |
| 258 | |
| 259 | std::string LocalDateTimeString() { |
| 260 | return DateTimeString(true); |
| 261 | } |
| 262 | |
| 263 | } // end namespace benchmark |
trunk/src/mame/drivers/fidelz80.cpp
| r253076 | r253077 | |
| 598 | 598 | PB.4 - white wire (and TSI BUSY line) |
| 599 | 599 | PB.5 - selection jumper input (see below) |
| 600 | 600 | PB.6 - TSI start line |
| 601 | | PB.7 - TSI ROM A12 line |
| 601 | PB.7 - TSI ROM D0 line |
| 602 | 602 | |
| 603 | 603 | |
| 604 | 604 | selection jumpers: |
| r253076 | r253077 | |
| 1070 | 1070 | { |
| 1071 | 1071 | // d0-d3: select digits |
| 1072 | 1072 | // d0-d7: select leds, input mux low bits |
| 1073 | | m_inp_mux = (m_inp_mux & ~0xff) | data; |
| 1073 | m_inp_mux = (m_inp_mux & 0x300) | data; |
| 1074 | 1074 | m_led_select = data; |
| 1075 | 1075 | vsc_prepare_display(); |
| 1076 | 1076 | } |
| r253076 | r253077 | |
| 1081 | 1081 | READ8_MEMBER(fidelz80_state::vsc_pio_porta_r) |
| 1082 | 1082 | { |
| 1083 | 1083 | // d0-d7: multiplexed inputs |
| 1084 | | return read_inputs(11); |
| 1085 | | |
| 1084 | return read_inputs(10); |
| 1086 | 1085 | } |
| 1087 | 1086 | |
| 1088 | 1087 | READ8_MEMBER(fidelz80_state::vsc_pio_portb_r) |
| r253076 | r253077 | |
| 1091 | 1090 | |
| 1092 | 1091 | // d4: TSI BUSY line |
| 1093 | 1092 | ret |= (m_speech->busy_r()) ? 0 : 0x10; |
| 1094 | | |
| 1093 | |
| 1095 | 1094 | return ret; |
| 1096 | 1095 | } |
| 1097 | 1096 | |
| 1098 | 1097 | WRITE8_MEMBER(fidelz80_state::vsc_pio_portb_w) |
| 1099 | 1098 | { |
| 1100 | 1099 | // d0,d1: input mux highest bits |
| 1101 | | // d5: enable language switch |
| 1102 | | m_inp_mux = (m_inp_mux & ~0x700) | (data << 8 & 0x300) | (data << 5 & 0x400); |
| 1103 | | |
| 1104 | | //if (m_inp_mux & 0x400) debugger_break(machine()); |
| 1105 | | |
| 1106 | | // d7: TSI ROM A12 |
| 1107 | | |
| 1108 | | m_speech->force_update(); // update stream to now |
| 1109 | | m_speech_bank = data >> 7 & 1; |
| 1110 | | |
| 1100 | m_inp_mux = (m_inp_mux & 0xff) | (data << 8 & 0x300); |
| 1101 | |
| 1111 | 1102 | // d6: TSI START line |
| 1112 | 1103 | m_speech->start_w(data >> 6 & 1); |
| 1113 | | |
| 1104 | |
| 1114 | 1105 | // d2: lower TSI volume |
| 1115 | 1106 | m_speech->set_output_gain(0, (data & 4) ? 0.5 : 1.0); |
| 1116 | 1107 | } |
| r253076 | r253077 | |
| 1307 | 1298 | PORT_START("IN.4") |
| 1308 | 1299 | PORT_BIT(0x0f, IP_ACTIVE_HIGH, IPT_UNUSED) |
| 1309 | 1300 | |
| 1310 | | PORT_START("LEVEL") // hardwired (VCC/GND?) |
| 1311 | | PORT_CONFNAME( 0x80, 0x00, "Maximum Levels" ) |
| 1312 | | PORT_CONFSETTING( 0x00, "10" ) // factory setting |
| 1301 | PORT_START("LEVEL") // factory setting |
| 1302 | PORT_CONFNAME( 0x80, 0x00, "PPI.B.7: Maximum Levels" ) |
| 1303 | PORT_CONFSETTING( 0x00, "10" ) |
| 1313 | 1304 | PORT_CONFSETTING( 0x80, "3" ) |
| 1314 | 1305 | INPUT_PORTS_END |
| 1315 | 1306 | |
| 1316 | 1307 | static INPUT_PORTS_START( vcc ) |
| 1317 | 1308 | PORT_INCLUDE( vcc_base ) |
| 1318 | 1309 | |
| 1319 | | PORT_START("IN.4") // PCB jumpers, not consumer accessible |
| 1320 | | PORT_CONFNAME( 0x01, 0x00, "Language: French" ) |
| 1310 | PORT_START("IN.4") // not consumer accessible |
| 1311 | PORT_CONFNAME( 0x01, 0x00, "PCB Jumper: French" ) |
| 1321 | 1312 | PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) |
| 1322 | 1313 | PORT_CONFSETTING( 0x01, DEF_STR( On ) ) |
| 1323 | | PORT_CONFNAME( 0x02, 0x00, "Language: Spanish" ) |
| 1314 | PORT_CONFNAME( 0x02, 0x00, "PCB Jumper: Spanish" ) |
| 1324 | 1315 | PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) |
| 1325 | 1316 | PORT_CONFSETTING( 0x02, DEF_STR( On ) ) |
| 1326 | | PORT_CONFNAME( 0x04, 0x00, "Language: German" ) |
| 1317 | PORT_CONFNAME( 0x04, 0x00, "PCB Jumper: German" ) |
| 1327 | 1318 | PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) |
| 1328 | 1319 | PORT_CONFSETTING( 0x04, DEF_STR( On ) ) |
| 1329 | | PORT_CONFNAME( 0x08, 0x00, "Language: Special" ) |
| 1320 | PORT_CONFNAME( 0x08, 0x00, "PCB Jumper: Special" ) |
| 1330 | 1321 | PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) |
| 1331 | 1322 | PORT_CONFSETTING( 0x08, DEF_STR( On ) ) |
| 1332 | 1323 | INPUT_PORTS_END |
| r253076 | r253077 | |
| 1335 | 1326 | PORT_INCLUDE( vcc ) |
| 1336 | 1327 | |
| 1337 | 1328 | PORT_MODIFY("IN.4") |
| 1338 | | PORT_CONFNAME( 0x01, 0x01, "Language: French" ) |
| 1329 | PORT_CONFNAME( 0x01, 0x01, "PCB Jumper: French" ) |
| 1339 | 1330 | PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) |
| 1340 | 1331 | PORT_CONFSETTING( 0x01, DEF_STR( On ) ) |
| 1341 | 1332 | INPUT_PORTS_END |
| r253076 | r253077 | |
| 1344 | 1335 | PORT_INCLUDE( vcc ) |
| 1345 | 1336 | |
| 1346 | 1337 | PORT_MODIFY("IN.4") |
| 1347 | | PORT_CONFNAME( 0x02, 0x02, "Language: Spanish" ) |
| 1338 | PORT_CONFNAME( 0x02, 0x02, "PCB Jumper: Spanish" ) |
| 1348 | 1339 | PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) |
| 1349 | 1340 | PORT_CONFSETTING( 0x02, DEF_STR( On ) ) |
| 1350 | 1341 | INPUT_PORTS_END |
| r253076 | r253077 | |
| 1353 | 1344 | PORT_INCLUDE( vcc ) |
| 1354 | 1345 | |
| 1355 | 1346 | PORT_MODIFY("IN.4") |
| 1356 | | PORT_CONFNAME( 0x04, 0x04, "Language: German" ) |
| 1347 | PORT_CONFNAME( 0x04, 0x04, "PCB Jumper: German" ) |
| 1357 | 1348 | PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) |
| 1358 | 1349 | PORT_CONFSETTING( 0x04, DEF_STR( On ) ) |
| 1359 | 1350 | INPUT_PORTS_END |
| r253076 | r253077 | |
| 1458 | 1449 | PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("DM") PORT_CODE(KEYCODE_M) |
| 1459 | 1450 | PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("ST") PORT_CODE(KEYCODE_S) |
| 1460 | 1451 | PORT_BIT(0xc0, IP_ACTIVE_HIGH, IPT_UNUSED) |
| 1461 | | |
| 1462 | | PORT_START("IN.10") // hardwired (2 diodes) |
| 1463 | | PORT_CONFNAME( 0x03, 0x00, "Language" ) |
| 1464 | | PORT_CONFSETTING( 0x00, "English" ) |
| 1465 | | PORT_CONFSETTING( 0x01, "1" ) // todo: game dasm says it checks against 0/not0, 2, 3.. which language is which? |
| 1466 | | PORT_CONFSETTING( 0x02, "2" ) |
| 1467 | | PORT_CONFSETTING( 0x03, "3" ) |
| 1468 | 1452 | INPUT_PORTS_END |
| 1469 | 1453 | |
| 1470 | 1454 | static INPUT_PORTS_START( vbrc ) |
| r253076 | r253077 | |
| 1598 | 1582 | /* sound hardware */ |
| 1599 | 1583 | MCFG_SPEAKER_STANDARD_MONO("mono") |
| 1600 | 1584 | MCFG_SOUND_ADD("speech", S14001A, 25000) // R/C circuit, around 25khz |
| 1601 | | MCFG_S14001A_EXT_READ_HANDLER(READ8(fidelz80_state, vcc_speech_r)) |
| 1602 | 1585 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.75) |
| 1603 | 1586 | MACHINE_CONFIG_END |
| 1604 | 1587 | |
| r253076 | r253077 | |
| 1722 | 1705 | ROM_LOAD("101-64109.bin", 0x2000, 0x2000, CRC(08a3577c) SHA1(69fe379d21a9d4b57c84c3832d7b3e7431eec341) ) |
| 1723 | 1706 | ROM_LOAD("101-32024.bin", 0x4000, 0x1000, CRC(2a078676) SHA1(db2f0aba7e8ac0f84a17bae7155210cdf0813afb) ) |
| 1724 | 1707 | |
| 1725 | | ROM_REGION( 0x2000, "speech", 0 ) |
| 1708 | ROM_REGION( 0x1000, "speech", 0 ) |
| 1726 | 1709 | ROM_LOAD("101-32107.bin", 0x0000, 0x1000, CRC(f35784f9) SHA1(348e54a7fa1e8091f89ac656b4da22f28ca2e44d) ) |
| 1727 | | ROM_RELOAD( 0x1000, 0x1000) |
| 1728 | 1710 | ROM_END |
| 1729 | 1711 | |
| 1730 | | ROM_START( vscsp ) |
| 1731 | | ROM_REGION( 0x10000, "maincpu", 0 ) |
| 1732 | | ROM_LOAD("101-64108.bin", 0x0000, 0x2000, CRC(c9c98490) SHA1(e6db883df088d60463e75db51433a4b01a3e7626) ) |
| 1733 | | ROM_LOAD("101-64109.bin", 0x2000, 0x2000, CRC(08a3577c) SHA1(69fe379d21a9d4b57c84c3832d7b3e7431eec341) ) |
| 1734 | | ROM_LOAD("101-32024.bin", 0x4000, 0x1000, CRC(2a078676) SHA1(db2f0aba7e8ac0f84a17bae7155210cdf0813afb) ) |
| 1735 | 1712 | |
| 1736 | | ROM_REGION( 0x2000, "speech", 0 ) |
| 1737 | | ROM_LOAD("vcc-spanish.bin", 0x0000, 0x2000, BAD_DUMP CRC(8766e128) SHA1(78c7413bf240159720b131ab70bfbdf4e86eb1e9) ) // taken from vcc/fexcelv, assume correct |
| 1738 | | ROM_END |
| 1739 | | |
| 1740 | | ROM_START( vscg ) |
| 1741 | | ROM_REGION( 0x10000, "maincpu", 0 ) |
| 1742 | | ROM_LOAD("101-64108.bin", 0x0000, 0x2000, CRC(c9c98490) SHA1(e6db883df088d60463e75db51433a4b01a3e7626) ) |
| 1743 | | ROM_LOAD("101-64109.bin", 0x2000, 0x2000, CRC(08a3577c) SHA1(69fe379d21a9d4b57c84c3832d7b3e7431eec341) ) |
| 1744 | | ROM_LOAD("101-32024.bin", 0x4000, 0x1000, CRC(2a078676) SHA1(db2f0aba7e8ac0f84a17bae7155210cdf0813afb) ) |
| 1745 | | |
| 1746 | | ROM_REGION( 0x2000, "speech", 0 ) |
| 1747 | | ROM_LOAD("vcc-german.bin", 0x0000, 0x2000, BAD_DUMP CRC(6c85e310) SHA1(20d1d6543c1e6a1f04184a2df2a468f33faec3ff) ) // taken from fexcelv, assume correct |
| 1748 | | ROM_END |
| 1749 | | |
| 1750 | | ROM_START( vscfr ) |
| 1751 | | ROM_REGION( 0x10000, "maincpu", 0 ) |
| 1752 | | ROM_LOAD("101-64108.bin", 0x0000, 0x2000, CRC(c9c98490) SHA1(e6db883df088d60463e75db51433a4b01a3e7626) ) |
| 1753 | | ROM_LOAD("101-64109.bin", 0x2000, 0x2000, CRC(08a3577c) SHA1(69fe379d21a9d4b57c84c3832d7b3e7431eec341) ) |
| 1754 | | ROM_LOAD("101-32024.bin", 0x4000, 0x1000, CRC(2a078676) SHA1(db2f0aba7e8ac0f84a17bae7155210cdf0813afb) ) |
| 1755 | | |
| 1756 | | ROM_REGION( 0x2000, "speech", 0 ) |
| 1757 | | ROM_LOAD("vcc-french.bin", 0x0000, 0x2000, BAD_DUMP CRC(fe8c5c18) SHA1(2b64279ab3747ee81c86963c13e78321c6cfa3a3) ) // taken from fexcelv, assume correct |
| 1758 | | ROM_END |
| 1759 | | |
| 1760 | | |
| 1761 | 1713 | ROM_START( vbrc ) // AKA model 7002 |
| 1762 | 1714 | ROM_REGION( 0x10000, "maincpu", 0 ) |
| 1763 | 1715 | // nec 2364 mask roms; pin 27 (PGM, probably NC here due to mask roms) goes to the pcb |
| r253076 | r253077 | |
| 1805 | 1757 | COMP( 1980, uvcg, vcc, 0, vcc, vccg, driver_device, 0, "Fidelity Electronics", "Advanced Voice Chess Challenger (German)", MACHINE_SUPPORTS_SAVE | MACHINE_NOT_WORKING ) |
| 1806 | 1758 | COMP( 1980, uvcfr, vcc, 0, vcc, vccfr, driver_device, 0, "Fidelity Electronics", "Advanced Voice Chess Challenger (French)", MACHINE_SUPPORTS_SAVE | MACHINE_NOT_WORKING ) |
| 1807 | 1759 | |
| 1808 | | COMP( 1980, vsc, 0, 0, vsc, vsc, driver_device, 0, "Fidelity Electronics", "Voice Sensory Chess Challenger (English)", MACHINE_SUPPORTS_SAVE | MACHINE_NOT_WORKING | MACHINE_CLICKABLE_ARTWORK ) |
| 1809 | | COMP( 1980, vscsp, vsc, 0, vsc, vsc, driver_device, 0, "Fidelity Electronics", "Voice Sensory Chess Challenger (Spanish)", MACHINE_SUPPORTS_SAVE | MACHINE_NOT_WORKING | MACHINE_CLICKABLE_ARTWORK ) |
| 1810 | | COMP( 1980, vscg, vsc, 0, vsc, vsc, driver_device, 0, "Fidelity Electronics", "Voice Sensory Chess Challenger (German)", MACHINE_SUPPORTS_SAVE | MACHINE_NOT_WORKING | MACHINE_CLICKABLE_ARTWORK ) |
| 1811 | | COMP( 1980, vscfr, vsc, 0, vsc, vsc, driver_device, 0, "Fidelity Electronics", "Voice Sensory Chess Challenger (French)", MACHINE_SUPPORTS_SAVE | MACHINE_NOT_WORKING | MACHINE_CLICKABLE_ARTWORK ) |
| 1760 | COMP( 1980, vsc, 0, 0, vsc, vsc, driver_device, 0, "Fidelity Electronics", "Voice Sensory Chess Challenger", MACHINE_SUPPORTS_SAVE | MACHINE_NOT_WORKING | MACHINE_CLICKABLE_ARTWORK ) |
| 1812 | 1761 | |
| 1813 | 1762 | COMP( 1979, vbrc, 0, 0, vbrc, vbrc, driver_device, 0, "Fidelity Electronics", "Voice Bridge Challenger", MACHINE_SUPPORTS_SAVE | MACHINE_NOT_WORKING ) |
| 1814 | 1763 | COMP( 1980, bridgec3, vbrc, 0, vbrc, vbrc, driver_device, 0, "Fidelity Electronics", "Voice Bridge Challenger III", MACHINE_SUPPORTS_SAVE | MACHINE_NOT_WORKING ) |
trunk/src/mame/drivers/hh_tms1k.cpp
| r253076 | r253077 | |
| 4909 | 4909 | CONS( 1980, mdndclab, 0, 0, mdndclab, mdndclab, driver_device, 0, "Mattel", "Dungeons & Dragons - Computer Labyrinth Game", MACHINE_SUPPORTS_SAVE ) // *** |
| 4910 | 4910 | |
| 4911 | 4911 | CONS( 1977, comp4, 0, 0, comp4, comp4, driver_device, 0, "Milton Bradley", "Comp IV", MACHINE_SUPPORTS_SAVE | MACHINE_NO_SOUND_HW ) |
| 4912 | | CONS( 1978, simon, 0, 0, simon, simon, driver_device, 0, "Milton Bradley", "Simon (Rev. A)", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK ) |
| 4913 | | CONS( 1979, ssimon, 0, 0, ssimon, ssimon, driver_device, 0, "Milton Bradley", "Super Simon", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK ) |
| 4912 | CONS( 1978, simon, 0, 0, simon, simon, driver_device, 0, "Milton Bradley", "Simon (Rev. A)", MACHINE_SUPPORTS_SAVE ) |
| 4913 | CONS( 1979, ssimon, 0, 0, ssimon, ssimon, driver_device, 0, "Milton Bradley", "Super Simon", MACHINE_SUPPORTS_SAVE ) |
| 4914 | 4914 | CONS( 1979, bigtrak, 0, 0, bigtrak, bigtrak, driver_device, 0, "Milton Bradley", "Big Trak", MACHINE_SUPPORTS_SAVE | MACHINE_MECHANICAL ) // *** |
| 4915 | 4915 | |
| 4916 | 4916 | CONS( 1977, cnsector, 0, 0, cnsector, cnsector, driver_device, 0, "Parker Brothers", "Code Name: Sector", MACHINE_SUPPORTS_SAVE | MACHINE_NO_SOUND_HW ) // *** |
| 4917 | | CONS( 1978, merlin, 0, 0, merlin, merlin, driver_device, 0, "Parker Brothers", "Merlin - The Electronic Wizard", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK ) |
| 4917 | CONS( 1978, merlin, 0, 0, merlin, merlin, driver_device, 0, "Parker Brothers", "Merlin - The Electronic Wizard", MACHINE_SUPPORTS_SAVE ) |
| 4918 | 4918 | CONS( 1979, stopthie, 0, 0, stopthief, stopthief, driver_device, 0, "Parker Brothers", "Stop Thief (Electronic Crime Scanner)", MACHINE_SUPPORTS_SAVE ) // *** |
| 4919 | 4919 | CONS( 1979, stopthiep, stopthie, 0, stopthief, stopthief, driver_device, 0, "Parker Brothers", "Stop Thief (Electronic Crime Scanner) (patent)", MACHINE_SUPPORTS_SAVE | MACHINE_NOT_WORKING ) |
| 4920 | 4920 | CONS( 1980, bankshot, 0, 0, bankshot, bankshot, driver_device, 0, "Parker Brothers", "Bank Shot - Electronic Pool", MACHINE_SUPPORTS_SAVE ) |
| 4921 | 4921 | CONS( 1980, splitsec, 0, 0, splitsec, splitsec, driver_device, 0, "Parker Brothers", "Split Second", MACHINE_SUPPORTS_SAVE ) |
| 4922 | | CONS( 1982, mmerlin, 0, 0, mmerlin, mmerlin, driver_device, 0, "Parker Brothers", "Master Merlin", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK ) |
| 4922 | CONS( 1982, mmerlin, 0, 0, mmerlin, mmerlin, driver_device, 0, "Parker Brothers", "Master Merlin", MACHINE_SUPPORTS_SAVE ) |
| 4923 | 4923 | |
| 4924 | | CONS( 1981, tandy12, 0, 0, tandy12, tandy12, driver_device, 0, "Tandy Radio Shack", "Tandy-12: Computerized Arcade", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK ) // some of the minigames: *** |
| 4924 | CONS( 1981, tandy12, 0, 0, tandy12, tandy12, driver_device, 0, "Tandy Radio Shack", "Tandy-12: Computerized Arcade", MACHINE_SUPPORTS_SAVE ) // some of the minigames: *** |
| 4925 | 4925 | |
| 4926 | 4926 | CONS( 1979, tbreakup, 0, 0, tbreakup, tbreakup, driver_device, 0, "Tomy", "Break Up (Tomy)", MACHINE_SUPPORTS_SAVE ) |
| 4927 | 4927 | CONS( 1980, phpball, 0, 0, phpball, phpball, driver_device, 0, "Tomy", "Power House Pinball", MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK ) |
trunk/src/mame/drivers/iteagle.cpp
| r253076 | r253077 | |
| 179 | 179 | |
| 180 | 180 | static MACHINE_CONFIG_DERIVED( gtfore01, iteagle ) |
| 181 | 181 | MCFG_DEVICE_MODIFY(PCI_ID_FPGA) |
| 182 | | MCFG_ITEAGLE_FPGA_INIT(0x00000401, 0x0b0b0b) |
| 182 | MCFG_ITEAGLE_FPGA_INIT(0x01000401, 0x0b0b0b) |
| 183 | 183 | MCFG_DEVICE_MODIFY(PCI_ID_EEPROM) |
| 184 | 184 | MCFG_ITEAGLE_EEPROM_INIT(0x0401, 0x7) |
| 185 | 185 | MACHINE_CONFIG_END |
| r253076 | r253077 | |
| 187 | 187 | static MACHINE_CONFIG_DERIVED( gtfore02, iteagle ) |
| 188 | 188 | MCFG_DEVICE_MODIFY(PCI_ID_FPGA) |
| 189 | 189 | MCFG_ITEAGLE_FPGA_INIT(0x01000402, 0x020201) |
| 190 | | MCFG_DEVICE_MODIFY(PCI_ID_EEPROM) |
| 190 | MCFG_DEVICE_MODIFY(":pci:0a.0") |
| 191 | 191 | MCFG_ITEAGLE_EEPROM_INIT(0x0402, 0x7) |
| 192 | 192 | MACHINE_CONFIG_END |
| 193 | 193 | |
| r253076 | r253077 | |
| 215 | 215 | static MACHINE_CONFIG_DERIVED( gtfore06, iteagle ) |
| 216 | 216 | MCFG_DEVICE_MODIFY(PCI_ID_FPGA) |
| 217 | 217 | MCFG_ITEAGLE_FPGA_INIT(0x01000406, 0x0c0b0d) |
| 218 | | MCFG_DEVICE_MODIFY(PCI_ID_EEPROM) |
| 218 | MCFG_DEVICE_MODIFY(":pci:0a.0") |
| 219 | 219 | MCFG_ITEAGLE_EEPROM_INIT(0x0406, 0x9); |
| 220 | 220 | MACHINE_CONFIG_END |
| 221 | 221 | |
| 222 | 222 | static MACHINE_CONFIG_DERIVED( carnking, iteagle ) |
| 223 | 223 | MCFG_DEVICE_MODIFY(PCI_ID_FPGA) |
| 224 | | MCFG_ITEAGLE_FPGA_INIT(0x01000a01, 0x0e0a0a) |
| 224 | MCFG_ITEAGLE_FPGA_INIT(0x01000603, 0x0c0b0d) |
| 225 | 225 | MCFG_DEVICE_MODIFY(PCI_ID_EEPROM) |
| 226 | | MCFG_ITEAGLE_EEPROM_INIT(0x0a01, 0x9) |
| 226 | MCFG_ITEAGLE_EEPROM_INIT(0x0603, 0x9) |
| 227 | 227 | MACHINE_CONFIG_END |
| 228 | 228 | |
| 229 | 229 | static MACHINE_CONFIG_DERIVED( bbhsc, iteagle ) |
| 230 | 230 | MCFG_DEVICE_MODIFY(PCI_ID_FPGA) |
| 231 | | MCFG_ITEAGLE_FPGA_INIT(0x02000600, 0x0c0a0a) |
| 231 | MCFG_ITEAGLE_FPGA_INIT(0x01000600, 0x0c0a0a) |
| 232 | 232 | MCFG_DEVICE_MODIFY(PCI_ID_EEPROM) |
| 233 | | MCFG_ITEAGLE_EEPROM_INIT(0x0000, 0x7) |
| 233 | MCFG_ITEAGLE_EEPROM_INIT(0x0600, 0x9) |
| 234 | 234 | MACHINE_CONFIG_END |
| 235 | 235 | |
| 236 | 236 | static MACHINE_CONFIG_DERIVED( bbhcotw, iteagle ) |
| 237 | 237 | MCFG_DEVICE_MODIFY(PCI_ID_FPGA) |
| 238 | 238 | MCFG_ITEAGLE_FPGA_INIT(0x02000603, 0x080704) |
| 239 | | MCFG_DEVICE_MODIFY(PCI_ID_EEPROM) |
| 239 | MCFG_DEVICE_MODIFY(":pci:0a.0") |
| 240 | 240 | MCFG_ITEAGLE_EEPROM_INIT(0x0603, 0x9) |
| 241 | 241 | MACHINE_CONFIG_END |
| 242 | 242 | |
| r253076 | r253077 | |
| 331 | 331 | |
| 332 | 332 | INPUT_PORTS_END |
| 333 | 333 | |
| 334 | | static INPUT_PORTS_START( bbh ) |
| 334 | static INPUT_PORTS_START( bbhcotw ) |
| 335 | 335 | PORT_INCLUDE( iteagle ) |
| 336 | 336 | |
| 337 | 337 | PORT_MODIFY("IN1") |
| r253076 | r253077 | |
| 557 | 557 | |
| 558 | 558 | GAME( 2000, iteagle, 0, iteagle, iteagle, driver_device, 0, ROT0, "Incredible Technologies", "Eagle BIOS", MACHINE_IS_BIOS_ROOT ) |
| 559 | 559 | GAME( 1998, virtpool, iteagle, virtpool, virtpool, driver_device, 0, ROT0, "Incredible Technologies", "Virtual Pool", MACHINE_NOT_WORKING ) // random lockups on loading screens |
| 560 | | GAME( 2002, carnking, iteagle, carnking, bbh, driver_device, 0, ROT0, "Incredible Technologies", "Carnival King (v1.00.11)", 0 ) |
| 560 | GAME( 2002, carnking, iteagle, carnking, iteagle, driver_device, 0, ROT0, "Incredible Technologies", "Carnival King (v1.00.11)", MACHINE_NOT_WORKING ) |
| 561 | 561 | GAME( 2000, gtfore01, iteagle, gtfore01, iteagle, driver_device, 0, ROT0, "Incredible Technologies", "Golden Tee Fore! (v1.00.25)", 0 ) |
| 562 | 562 | GAME( 2001, gtfore02, iteagle, gtfore02, iteagle, driver_device, 0, ROT0, "Incredible Technologies", "Golden Tee Fore! 2002 (v2.01.06)", 0 ) |
| 563 | 563 | GAME( 2002, gtfore03, iteagle, gtfore03, iteagle, driver_device, 0, ROT0, "Incredible Technologies", "Golden Tee Fore! 2003 (v3.00.10)", 0 ) |
| r253076 | r253077 | |
| 569 | 569 | GAME( 2004, gtfore05b, gtfore05, gtfore05, iteagle, driver_device, 0, ROT0, "Incredible Technologies", "Golden Tee Fore! 2005 Extra (v5.01.00)", 0 ) |
| 570 | 570 | GAME( 2004, gtfore05c, gtfore05, gtfore05, iteagle, driver_device, 0, ROT0, "Incredible Technologies", "Golden Tee Fore! 2005 Extra (v5.00.00)", 0 ) |
| 571 | 571 | GAME( 2005, gtfore06, iteagle, gtfore06, iteagle, driver_device, 0, ROT0, "Incredible Technologies", "Golden Tee Fore! 2006 Complete (v6.00.01)", 0 ) |
| 572 | | GAME( 2002, bbhsc, iteagle, bbhsc, bbh, driver_device, 0, ROT0, "Incredible Technologies", "Big Buck Hunter - Shooter's Challenge (v1.50.07)", MACHINE_NOT_WORKING ) // doesn't boot |
| 573 | | GAME( 2006, bbhcotw, iteagle, bbhcotw, bbh, driver_device, 0, ROT0, "Incredible Technologies", "Big Buck Hunter Call of the Wild (v3.02.5)", MACHINE_NOT_WORKING ) // random lockups |
| 572 | GAME( 2002, bbhsc, iteagle, bbhsc, iteagle, driver_device, 0, ROT0, "Incredible Technologies", "Big Buck Hunter - Shooter's Challenge (v1.50.07)", MACHINE_NOT_WORKING ) // doesn't boot |
| 573 | GAME( 2006, bbhcotw, iteagle, bbhcotw, bbhcotw, driver_device, 0, ROT0, "Incredible Technologies", "Big Buck Hunter Call of the Wild (v3.02.5)", MACHINE_NOT_WORKING ) // random lockups |
trunk/src/mame/drivers/overdriv.cpp
| r253076 | r253077 | |
| 70 | 70 | |
| 71 | 71 | TIMER_DEVICE_CALLBACK_MEMBER(overdriv_state::overdriv_cpuA_scanline) |
| 72 | 72 | { |
| 73 | | const int timer_threshold = 168; // fwiw matches 0 on mask ROM check, so IF it's a timer irq then should be close ... |
| 74 | 73 | int scanline = param; |
| 75 | | |
| 76 | | m_fake_timer ++; |
| 77 | | |
| 78 | | // TODO: irqs routines are TOO slow right now, it ends up firing spurious irqs for whatever reason (shared ram fighting?) |
| 79 | | // this is a temporary solution to get rid of deprecat lib and the crashes, but also makes the game timer to be too slow. |
| 80 | | // Update: gameplay is actually too fast compared to timer, first attract mode shouldn't even surpass first blue car on right. |
| 81 | | if(scanline == 256) // vblank-out irq |
| 82 | | { |
| 83 | | // m_screen->frame_number() & 1 |
| 74 | |
| 75 | /* TODO: irqs routines are TOO slow right now, it ends up firing spurious irqs for whatever reason (shared ram fighting?) */ |
| 76 | /* this is a temporary solution to get rid of deprecat lib and the crashes, but also makes the game timer to be too slow */ |
| 77 | if(scanline == 256 && m_screen->frame_number() & 1) // vblank-out irq |
| 84 | 78 | m_maincpu->set_input_line(4, HOLD_LINE); |
| 85 | | m_subcpu->set_input_line(4, HOLD_LINE); // likely wrong |
| 86 | | } |
| 87 | | else if(m_fake_timer >= timer_threshold) // timer irq |
| 88 | | { |
| 89 | | m_fake_timer -= timer_threshold; |
| 79 | else if((scanline % 128) == 0) // timer irq |
| 90 | 80 | m_maincpu->set_input_line(5, HOLD_LINE); |
| 91 | | } |
| 92 | 81 | } |
| 93 | 82 | |
| 94 | 83 | INTERRUPT_GEN_MEMBER(overdriv_state::cpuB_interrupt) |
| 95 | 84 | { |
| 96 | 85 | // this doesn't get turned on until the irq has happened? wrong irq? |
| 97 | | if (m_k053246->k053246_is_irq_enabled()) |
| 98 | | m_subcpu->set_input_line(6, HOLD_LINE); // likely wrong |
| 86 | // if (m_k053246->k053246_is_irq_enabled()) |
| 87 | m_subcpu->set_input_line(4, HOLD_LINE); // likely wrong |
| 99 | 88 | } |
| 100 | 89 | |
| 101 | 90 | |
| r253076 | r253077 | |
| 138 | 127 | |
| 139 | 128 | WRITE16_MEMBER(overdriv_state::overdriv_soundirq_w) |
| 140 | 129 | { |
| 141 | | m_audiocpu->set_input_line(M6809_IRQ_LINE, ASSERT_LINE); |
| 130 | m_audiocpu->set_input_line(M6809_IRQ_LINE, HOLD_LINE); |
| 142 | 131 | } |
| 143 | 132 | |
| 144 | | |
| 145 | 133 | WRITE16_MEMBER(overdriv_state::overdriv_cpuB_irq_x_w) |
| 146 | 134 | { |
| 147 | 135 | m_subcpu->set_input_line(5, HOLD_LINE); // likely wrong |
| r253076 | r253077 | |
| 149 | 137 | |
| 150 | 138 | WRITE16_MEMBER(overdriv_state::overdriv_cpuB_irq_y_w) |
| 151 | 139 | { |
| 140 | m_subcpu->set_input_line(6, HOLD_LINE); // likely wrong |
| 152 | 141 | } |
| 153 | 142 | |
| 154 | 143 | static ADDRESS_MAP_START( overdriv_master_map, AS_PROGRAM, 16, overdriv_state ) |
| r253076 | r253077 | |
| 178 | 167 | AM_RANGE(0x238000, 0x238001) AM_WRITE(overdriv_cpuB_irq_x_w) |
| 179 | 168 | ADDRESS_MAP_END |
| 180 | 169 | |
| 181 | | #ifdef UNUSED_FUNCTION |
| 170 | // HACK ALERT |
| 182 | 171 | WRITE16_MEMBER( overdriv_state::overdriv_k053246_word_w ) |
| 183 | 172 | { |
| 184 | 173 | m_k053246->k053246_word_w(space,offset,data,mem_mask); |
| r253076 | r253077 | |
| 201 | 190 | //printf("%02x %04x %04x\n", offset, data, mem_mask); |
| 202 | 191 | |
| 203 | 192 | } |
| 204 | | #endif |
| 205 | 193 | |
| 206 | 194 | static ADDRESS_MAP_START( overdriv_slave_map, AS_PROGRAM, 16, overdriv_state ) |
| 207 | 195 | AM_RANGE(0x000000, 0x03ffff) AM_ROM |
| r253076 | r253077 | |
| 209 | 197 | AM_RANGE(0x0c0000, 0x0c1fff) AM_RAM //AM_DEVREADWRITE("k053250_1", k053250_device, ram_r, ram_w) |
| 210 | 198 | AM_RANGE(0x100000, 0x10000f) AM_DEVREADWRITE("k053250_1", k053250_device, reg_r, reg_w) |
| 211 | 199 | AM_RANGE(0x108000, 0x10800f) AM_DEVREADWRITE("k053250_2", k053250_device, reg_r, reg_w) |
| 212 | | AM_RANGE(0x118000, 0x118fff) AM_DEVREADWRITE("k053246", k053247_device, k053247_word_r, k053247_word_w) // data gets copied to sprite chip with DMA.. |
| 200 | AM_RANGE(0x118000, 0x118fff) AM_RAM AM_SHARE("sprram") //AM_DEVREADWRITE("k053246", k053247_device, k053247_word_r, k053247_word_w) // data gets copied to sprite chip with DMA.. |
| 213 | 201 | AM_RANGE(0x120000, 0x120001) AM_DEVREAD("k053246", k053247_device, k053246_word_r) |
| 214 | 202 | AM_RANGE(0x128000, 0x128001) AM_READWRITE(cpuB_ctrl_r, cpuB_ctrl_w) /* enable K053247 ROM reading, plus something else */ |
| 215 | | AM_RANGE(0x130000, 0x130007) AM_DEVREADWRITE8("k053246", k053247_device, k053246_r,k053246_w,0xffff) |
| 216 | | //AM_RANGE(0x140000, 0x140001) used in later stages |
| 203 | AM_RANGE(0x130000, 0x130007) AM_WRITE(overdriv_k053246_word_w) // AM_DEVWRITE("k053246", k053247_device, k053246_word_w) |
| 217 | 204 | AM_RANGE(0x200000, 0x203fff) AM_RAM AM_SHARE("share1") |
| 218 | 205 | AM_RANGE(0x208000, 0x20bfff) AM_RAM |
| 219 | 206 | AM_RANGE(0x218000, 0x219fff) AM_DEVREAD("k053250_1", k053250_device, rom_r) |
| 220 | 207 | AM_RANGE(0x220000, 0x221fff) AM_DEVREAD("k053250_2", k053250_device, rom_r) |
| 221 | 208 | ADDRESS_MAP_END |
| 222 | 209 | |
| 223 | | WRITE8_MEMBER(overdriv_state::sound_ack_w) |
| 224 | | { |
| 225 | | m_audiocpu->set_input_line(M6809_IRQ_LINE, CLEAR_LINE); |
| 226 | | } |
| 227 | | |
| 228 | 210 | static ADDRESS_MAP_START( overdriv_sound_map, AS_PROGRAM, 8, overdriv_state ) |
| 229 | | AM_RANGE(0x0000, 0x0000) AM_WRITE(sound_ack_w) |
| 230 | | // 0x012 read during explosions |
| 231 | | // 0x180 |
| 232 | 211 | AM_RANGE(0x0200, 0x0201) AM_DEVREADWRITE("ymsnd", ym2151_device,read,write) |
| 233 | 212 | AM_RANGE(0x0400, 0x042f) AM_DEVREADWRITE("k053260_1", k053260_device, read, write) |
| 234 | 213 | AM_RANGE(0x0600, 0x062f) AM_DEVREADWRITE("k053260_2", k053260_device, read, write) |
| r253076 | r253077 | |
| 243 | 222 | |
| 244 | 223 | static INPUT_PORTS_START( overdriv ) |
| 245 | 224 | PORT_START("INPUTS") |
| 246 | | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_TOGGLE |
| 225 | PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_TOGGLE |
| 247 | 226 | PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON1 ) |
| 248 | 227 | PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON2 ) |
| 249 | 228 | PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| r253076 | r253077 | |
| 318 | 297 | |
| 319 | 298 | /* video hardware */ |
| 320 | 299 | MCFG_SCREEN_ADD("screen", RASTER) |
| 321 | | MCFG_SCREEN_RAW_PARAMS(XTAL_24MHz/4,384,0,305,264,0,224) |
| 300 | MCFG_SCREEN_REFRESH_RATE(59) |
| 301 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) |
| 302 | MCFG_SCREEN_SIZE(64*8, 40*8) |
| 303 | MCFG_SCREEN_VISIBLE_AREA(13*8, (64-13)*8-1, 0*8, 32*8-1 ) |
| 322 | 304 | MCFG_SCREEN_UPDATE_DRIVER(overdriv_state, screen_update_overdriv) |
| 323 | 305 | MCFG_SCREEN_PALETTE("palette") |
| 324 | 306 | |
| r253076 | r253077 | |
| 493 | 475 | ROM_LOAD( "789e02.f1", 0x100000, 0x100000, CRC(bdd3b5c6) SHA1(412332d64052c0a3714f4002c944b0e7d32980a4) ) |
| 494 | 476 | ROM_END |
| 495 | 477 | |
| 496 | | GAMEL( 1990, overdriv, 0, overdriv, overdriv, driver_device, 0, ROT90, "Konami", "Over Drive (set 1)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE, layout_overdriv ) // US version |
| 497 | | GAMEL( 1990, overdriva, overdriv, overdriv, overdriv, driver_device, 0, ROT90, "Konami", "Over Drive (set 2)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE, layout_overdriv ) // Overseas? |
| 498 | | GAMEL( 1990, overdrivb, overdriv, overdriv, overdriv, driver_device, 0, ROT90, "Konami", "Over Drive (set 3)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE, layout_overdriv ) // Overseas? |
| 478 | GAMEL( 1990, overdriv, 0, overdriv, overdriv, driver_device, 0, ROT90, "Konami", "Over Drive (set 1)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE, layout_overdriv ) |
| 479 | GAMEL( 1990, overdriva, overdriv, overdriv, overdriv, driver_device, 0, ROT90, "Konami", "Over Drive (set 2)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE, layout_overdriv ) |
| 480 | GAMEL( 1990, overdrivb, overdriv, overdriv, overdriv, driver_device, 0, ROT90, "Konami", "Over Drive (set 3)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE, layout_overdriv ) |
trunk/src/mame/machine/iteagle_fpga.cpp
| r253076 | r253077 | |
| 4 | 4 | #include "coreutil.h" |
| 5 | 5 | |
| 6 | 6 | #define LOG_FPGA (0) |
| 7 | | #define LOG_SERIAL (0) |
| 8 | 7 | #define LOG_RTC (0) |
| 9 | 8 | #define LOG_RAM (0) |
| 10 | 9 | #define LOG_EEPROM (0) |
| r253076 | r253077 | |
| 81 | 80 | m_serial_str.clear(); |
| 82 | 81 | m_serial_idx = 0; |
| 83 | 82 | m_serial_data = false; |
| 84 | | memset(m_serial_com0, 0, sizeof(m_serial_com0)); |
| 85 | 83 | memset(m_serial_com1, 0, sizeof(m_serial_com1)); |
| 86 | 84 | memset(m_serial_com2, 0, sizeof(m_serial_com2)); |
| 87 | 85 | memset(m_serial_com3, 0, sizeof(m_serial_com3)); |
| 88 | | m_serial_com0[0] = 0x2c; |
| 86 | memset(m_serial_com4, 0, sizeof(m_serial_com4)); |
| 89 | 87 | m_serial_com1[0] = 0x2c; |
| 90 | 88 | m_serial_com2[0] = 0x2c; |
| 91 | 89 | m_serial_com3[0] = 0x2c; |
| 90 | m_serial_com4[0] = 0x2c; |
| 92 | 91 | } |
| 93 | 92 | |
| 94 | 93 | void iteagle_fpga_device::update_sequence(UINT32 data) |
| r253076 | r253077 | |
| 131 | 130 | val1 = ((m_seq & 0x2)<<6) | ((m_seq & 0x4)<<4) | ((m_seq & 0x8)<<2) | ((m_seq & 0x10)<<0) |
| 132 | 131 | | ((m_seq & 0x20)>>2) | ((m_seq & 0x40)>>4) | ((m_seq & 0x80)>>6) | ((m_seq & 0x100)>>8); |
| 133 | 132 | m_seq = (m_seq>>8) | ((feed&0xff)<<16); |
| 133 | //m_fpga_regs[offset] = (m_fpga_regs[offset]&0xFFFFFF00) | ((val1 + m_seq_rem1)&0xFF); |
| 134 | 134 | m_fpga_regs[offset] = (m_fpga_regs[offset]&0xFFFFFF00) | ((val1 + m_seq_rem1 + m_seq_rem2)&0xFF); |
| 135 | 135 | } else if (data & 0x2) { |
| 136 | 136 | val1 = ((m_seq & 0x2)<<1) | ((m_seq & 0x4)>>1) | ((m_seq & 0x8)>>3); |
| 137 | 137 | m_seq_rem1 = ((m_seq & 0x10)) | ((m_seq & 0x20)>>2) | ((m_seq & 0x40)>>4); |
| 138 | //m_seq_rem2 = ((m_seq & 0x80)>>1) | ((m_seq & 0x100)>>3) | ((m_seq & 0x200)>>5); |
| 138 | 139 | m_seq = (m_seq>>6) | ((feed&0x3f)<<18); |
| 139 | 140 | m_fpga_regs[offset] = (m_fpga_regs[offset]&0xFFFFFF00) | ((val1 + m_seq_rem1 + m_seq_rem2)&0xFF); |
| 140 | 141 | } else { |
| r253076 | r253077 | |
| 196 | 197 | logerror("%s:fpga_r offset %04X = %08X & %08X\n", machine().describe_context(), offset*4, result, mem_mask); |
| 197 | 198 | break; |
| 198 | 199 | case 0x0c/4: // 1d = modem byte |
| 199 | | result = (result & 0xFFFF0000) | ((m_serial_com1[m_serial_idx]&0xff)<<8) | (m_serial_com0[m_serial_idx]&0xff); |
| 200 | result = (result & 0xFFFF0000) | ((m_serial_com2[m_serial_idx]&0xff)<<8) | (m_serial_com1[m_serial_idx]&0xff); |
| 200 | 201 | if (ACCESSING_BITS_0_15) { |
| 201 | 202 | m_serial_data = false; |
| 202 | 203 | m_serial_idx = 0; |
| 203 | 204 | } |
| 204 | | if (0 && LOG_FPGA) |
| 205 | if (LOG_FPGA) |
| 205 | 206 | logerror("%s:fpga_r offset %04X = %08X & %08X\n", machine().describe_context(), offset*4, result, mem_mask); |
| 206 | 207 | break; |
| 207 | 208 | case 0x1c/4: // 1d = modem byte |
| 208 | | result = (result & 0xFFFF0000) | ((m_serial_com3[m_serial_idx]&0xff)<<8) | (m_serial_com2[m_serial_idx]&0xff); |
| 209 | result = (result & 0xFFFF0000) | ((m_serial_com4[m_serial_idx]&0xff)<<8) | (m_serial_com3[m_serial_idx]&0xff); |
| 209 | 210 | if (ACCESSING_BITS_0_15) { |
| 210 | 211 | m_serial_data = false; |
| 211 | 212 | m_serial_idx = 0; |
| r253076 | r253077 | |
| 232 | 233 | if ((m_version & 0xff00) == 0x0200) |
| 233 | 234 | update_sequence_eg1(data & 0xff); |
| 234 | 235 | else |
| 235 | | // ATMEL Chip access. Returns version id's when bit 7 is set. |
| 236 | | update_sequence(data & 0xff); |
| 236 | // ATMEL Chip access. Returns version id's when bit 7 is set. |
| 237 | update_sequence(data & 0xff); |
| 237 | 238 | if (0 && LOG_FPGA) |
| 238 | 239 | logerror("%s:fpga_w offset %04X = %08X & %08X\n", machine().describe_context(), offset*4, data, mem_mask); |
| 239 | 240 | } |
| r253076 | r253077 | |
| 241 | 242 | if (ACCESSING_BITS_24_31 && (data & 0x01000000)) { |
| 242 | 243 | m_cpu->set_input_line(m_irq_num, CLEAR_LINE); |
| 243 | 244 | // Not sure what value to use here, needed for lightgun |
| 244 | | m_timer->adjust(attotime::from_hz(59)); |
| 245 | m_timer->adjust(attotime::from_hz(25)); |
| 245 | 246 | if (LOG_FPGA) |
| 246 | 247 | logerror("%s:fpga_w offset %04X = %08X & %08X Clearing interrupt(%i)\n", machine().describe_context(), offset*4, data, mem_mask, m_irq_num); |
| 247 | 248 | } else { |
| r253076 | r253077 | |
| 268 | 269 | if (!m_serial_data) { |
| 269 | 270 | m_serial_idx = data&0xf; |
| 270 | 271 | } else { |
| 271 | | m_serial_com0[m_serial_idx] = data&0xff; |
| 272 | m_serial_com1[m_serial_idx] = data&0xff; |
| 272 | 273 | m_serial_idx = 0; |
| 273 | 274 | } |
| 274 | 275 | m_serial_data = !m_serial_data; |
| r253076 | r253077 | |
| 277 | 278 | if (!m_serial_data) { |
| 278 | 279 | m_serial_idx = (data&0x0f00)>>8; |
| 279 | 280 | } else { |
| 280 | | m_serial_com1[m_serial_idx] = (data&0xff00)>>8; |
| 281 | m_serial_com2[m_serial_idx] = (data&0xff00)>>8; |
| 281 | 282 | } |
| 282 | 283 | m_serial_data = !m_serial_data; |
| 283 | 284 | } |
| 284 | 285 | if (ACCESSING_BITS_16_23) { |
| 285 | 286 | if (m_serial_str.size()==0) |
| 286 | | m_serial_str = "com0: "; |
| 287 | m_serial_str = "com1: "; |
| 287 | 288 | m_serial_str += (data>>16)&0xff; |
| 288 | 289 | if (((data>>16)&0xff)==0xd) { |
| 289 | | if (LOG_SERIAL) logerror("%s\n", m_serial_str.c_str()); |
| 290 | 290 | osd_printf_debug("%s\n", m_serial_str.c_str()); |
| 291 | 291 | m_serial_str.clear(); |
| 292 | 292 | } |
| 293 | 293 | } |
| 294 | 294 | if (ACCESSING_BITS_24_31) { |
| 295 | 295 | if (m_serial_str.size()==0) |
| 296 | | m_serial_str = "com1: "; |
| 296 | m_serial_str = "com2: "; |
| 297 | 297 | m_serial_str += (data>>24)&0xff; |
| 298 | 298 | if (1 || ((data>>24)&0xff)==0xd) { |
| 299 | | if (LOG_SERIAL) logerror("%s\n", m_serial_str.c_str()); |
| 300 | 299 | osd_printf_debug("%s\n", m_serial_str.c_str()); |
| 301 | 300 | m_serial_str.clear(); |
| 302 | 301 | } |
| 303 | 302 | } |
| 304 | | if (0 && LOG_FPGA) |
| 303 | if (LOG_FPGA) |
| 305 | 304 | logerror("%s:fpga_w offset %04X = %08X & %08X\n", machine().describe_context(), offset*4, data, mem_mask); |
| 306 | 305 | break; |
| 307 | 306 | case 0x1c/4: |
| r253076 | r253077 | |
| 309 | 308 | if (!m_serial_data) { |
| 310 | 309 | m_serial_idx = data&0xf; |
| 311 | 310 | } else { |
| 312 | | m_serial_com2[m_serial_idx] = data&0xff; |
| 311 | m_serial_com3[m_serial_idx] = data&0xff; |
| 313 | 312 | m_serial_idx = 0; |
| 314 | 313 | } |
| 315 | 314 | m_serial_data = !m_serial_data; |
| r253076 | r253077 | |
| 318 | 317 | if (!m_serial_data) { |
| 319 | 318 | m_serial_idx = (data&0x0f00)>>8; |
| 320 | 319 | } else { |
| 321 | | m_serial_com3[m_serial_idx] = (data&0xff00)>>8; |
| 320 | m_serial_com4[m_serial_idx] = (data&0xff00)>>8; |
| 322 | 321 | } |
| 323 | 322 | m_serial_data = !m_serial_data; |
| 324 | 323 | } |
| 325 | 324 | if (ACCESSING_BITS_16_23) { |
| 326 | 325 | if (m_serial_str.size()==0) |
| 327 | | m_serial_str = "com2: "; |
| 326 | m_serial_str = "com3: "; |
| 328 | 327 | m_serial_str += (data>>16)&0xff; |
| 329 | 328 | if (1 || ((data>>16)&0xff)==0xd) { |
| 330 | | if (LOG_SERIAL) logerror("%s\n", m_serial_str.c_str()); |
| 331 | 329 | osd_printf_debug("%s\n", m_serial_str.c_str()); |
| 332 | 330 | m_serial_str.clear(); |
| 333 | 331 | } |
| 334 | 332 | } |
| 335 | 333 | if (ACCESSING_BITS_24_31) { |
| 336 | 334 | if (m_serial_str.size()==0) |
| 337 | | m_serial_str = "com3: "; |
| 335 | m_serial_str = "com4: "; |
| 338 | 336 | m_serial_str += (data>>24)&0xff; |
| 339 | 337 | if (((data>>24)&0xff)==0xd) { |
| 340 | | if (LOG_SERIAL) logerror("%s\n", m_serial_str.c_str()); |
| 341 | 338 | osd_printf_debug("%s\n", m_serial_str.c_str()); |
| 342 | 339 | m_serial_str.clear(); |
| 343 | 340 | } |
| r253076 | r253077 | |
| 652 | 649 | { |
| 653 | 650 | pci_device::device_reset(); |
| 654 | 651 | memset(m_ctrl_regs, 0, sizeof(m_ctrl_regs)); |
| 655 | | m_ctrl_regs[0x10/4] = 0x00070000; // 0x6=No SIMM, 0x2, 0x1, 0x0 = SIMM . Top 16 bits are compared to 0x3. Bit 0 might be lan chip present. |
| 652 | m_ctrl_regs[0x10/4] = 0x00000000; // 0x6=No SIMM, 0x2, 0x1, 0x0 = SIMM . Top 16 bits are compared to 0x3. |
| 656 | 653 | memset(m_rtc_regs, 0, sizeof(m_rtc_regs)); |
| 657 | 654 | m_rtc_regs[0xa] = 0x20; // 32.768 MHz |
| 658 | 655 | m_rtc_regs[0xb] = 0x02; // 24-hour format |