├── .gitignore ├── CHANGELOG.md ├── ImageMagick.tgz ├── LICENSE ├── README.md ├── fftw ├── build.sh ├── fftw3.h ├── fftwtest.cpp ├── libfftw3.a ├── libfftw3_omp.a └── libfftw3_threads.a ├── fftwtest ├── gfxCardStatus.tgz ├── macoh.conf ├── macoh.sh ├── make-release.sh └── mprime.tgz /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *~ 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Changelog 2 | ========= 3 | 4 | - 1.5.5, 2020-08-06 - Updated intel power gadget url and fetch 5 | - 1.5.4, 2016-04-27 - Updated urls for the BBB movie and the newest Intel Power Gadget (Core M compatible) 6 | - 1.5.3, 2015-08-14 - Fixed dependencies for FFT test 7 | - 1.5.2, 2015-03-11 - Fixed graph missing labels (tex problem) 8 | - 1.5.1, 2015-03-10 - Fixed FFT binary and number of default threads (cores - 1) 9 | - 1.5.0, 2015-03-10 - Plots power draw, indicate stats, detects Tmax and TDP overruns 10 | - 1.4.0, 2015-03-09 - Added my own FFT test (emulates humane CPU stress, should not throttle) 11 | - 1.3.4-beta, 2015-03-08 - Fixed Handbrake URL 12 | - 1.3.1-beta, 2014-05-26 - User defined command timeout fix 13 | - 1.3.0-beta, 2014-05-13 - Compiled Prime95 for command line (mprime), Prime95 can be started automatically, added Prime95 menu options, separate GpuTest and Prime95 durations in menu, cleaner menu, some bug fixes 14 | - 1.2.3-beta, 2014-05-11 - More compact menu 15 | - 1.2.2-beta, 2014-05-11 - Safer CPU priority code; fixed bug in perf stats between multiple runs 16 | - 1.2.1-beta, 2014-05-11 - CPU priority of HandBrake and GpuTest can now be changed (menu, conf); more bug fixes. 17 | - 1.2.0-beta, 2014-05-09 - GpuTest stats on graphs, cleaner code, lots of bug fixes 18 | - 1.1.2-beta, 2014-05-08 - Added GPU switching to command line. 19 | - 1.1.1-beta, 2014-05-07 - Bug fixing release. 20 | - 1.1.0-beta, 2014-05-06 - Added GpuTest, Prime95, gfxCardStatus, longer x264 test, more command line options. 21 | - 1.0.1-alpha, 2014-05-03 - Added command line options to bypass menu 22 | - 1.0.0-alpha, 2014-05-02 - First version 23 | -------------------------------------------------------------------------------- /ImageMagick.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qnxor/macoh/5f9195a515f04198b40b2021ca25f2caca26c054/ImageMagick.tgz -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | MacOH 2 | ===== 3 | 4 | Small tool for Mac OS X runs CPU and GPU stress tests, monitoring CPU frequency, temperature and power draw which are plotted versus time. The purpose is to evaluate CPU throttling and/or overheating (not performance). 5 | 6 | Output examples: [x264](http://www.damtp.cam.ac.uk/research/afha/people/bogdan/macoh/x264.png) (no throttling), [Prime95](http://www.damtp.cam.ac.uk/research/afha/people/bogdan/macoh/prime95.png) (heavy throttling), [3D-Intel 5100](http://www.damtp.cam.ac.uk/research/afha/people/bogdan/macoh/gputest-irispro.png) (throttling), [3D-Nvidia 750M](http://www.damtp.cam.ac.uk/research/afha/people/bogdan/macoh/gputest-gt750m.png) (no throttling). 7 | 8 | - Can do FFTs, x264 encodes, Prime95, GpuTest or a custom command/script of your choice 9 | - Monitors and logs CPU temperature and frequency during the test 10 | - Plots a graph of CPU temperature and frequency vs. time 11 | - Grabs free and open source tools as needed: [Intel Power Gadget](https://software.intel.com/en-us/articles/intel-power-gadget-20) (measuring and logging), [HandBrake CLI](http://handbrake.fr) (x264 transcoding), [Prime95](http://mersenne.org) (CPU stress), [GpuTest](http://www.geeks3d.com/gputest/) (GPU stress), [gfxCardStatus](http://gfx.io) (GPU switching), [Ggraphics Layout Engine](http://glx.sourceforge.net) (graph plotting), [ImageMagick](http://www.imagemagick.org) (better image processing than sips) 12 | - Grabs the free movie [Big Buck Bunny](http://www.bigbuckbunny.org) in 1080p (692 MB) as needed 13 | 14 | I recommend the FFT test with as many threads as physical cores (this is the default). This is more stressful than most common operations one typically does, but less stressful than the x264 test or Prime95 test. If the FFT test with half the threads is throttling then you have a real problem (2 threads for a quad core CPU). Expect Prime95 to cause heavy throttling on laptops. The x264 test is in between but (on my rMBP at least) it still causes higher power draw than the TDP limit which can trigger throttling. The 3D GpuTest, when run on integrated GPU, can also cause CPU throttling. 15 | 16 | Feedback 17 | -------- 18 | 19 | The [dedicated thread on MacRumors forums](http://forums.macrumors.com/showthread.php?t=1731178) started containing results and discussions. Your contribution there would be very welcome. If it doesn't work for you, or if you find bugs, have suggestions, questions or comments then [drop a line on Github](https://github.com/qnxor/macoh/issues) or just [contact](http://www.damtp.cam.ac.uk/user/abr28) me. 20 | 21 | **Disclaimer:** As per the usual nitty gritty, I cannot be held responsible if your spouse leaves you after running this tool, or worse: if your Mac gets damaged. Most likely you'll be just fine though. 22 | 23 | Usage 24 | ----- 25 | 26 | 1. [Donwload](https://github.com/qnxor/macoh/releases) the latest .zip release and extract it somewhere 27 | 1. Open Terminal and do `bash macoh.sh` 28 | 1. Choose a command in the (old school) menu 29 | 30 | #### Config file 31 | 32 | There is a `macoh.conf` configuration file which you can edit it to set various options (defaults). It is sourced by Bash in the main script so make sure you use valid Bash syntax. 33 | 34 | #### Command line alternative 35 | 36 | `bash macoh.sh [-OPTION VALUE [-OPTION VALUE ...]]` 37 | 38 | Where -OPTION VALUE can be: 39 | 40 | - `-do` - launch a test, one of: *x264*, *x264-long*, *gputest*, *prime95* 41 | - `-get` - fetch one of: *ipg*, *gle*, *gfx*, *imagick*, *video*, *handbrake*, *gputest*, *prime95*. These are downloaded as necessary upon launching of a test but can be invoked separately. The script will prompt if it detects already downloaded/installed items. Downloads are placed in $HOME/macoh/tmp and installations in $HOME/macoh/bin. 42 | - `-cmd` - A user defined command to execute and monitor. This must be the last option in the command line, everything after it is considered part of the user command. You can use this to launch your own stress test to be monitored and have the temp and freq vs time plotted. The command must not terminate immediately (e.g. do not use ''open MyBenchmark.app''). Also take note of the duration value (`-t`) below. The -cmd option needs more thorough testing, please report bugs. 43 | - `-t,-time` - duration of Prime95, GpuTest and user defined command in seconds, use 0 to run indefinitely (default is 600 for GpuTest and 300 for the rest, see macoh.conf). Prime95 and the user defined command are assumed to run indefintely by default, so this option is used to stop them, unless they exit or if you abort them early. 44 | - `-w,-wait` - waiting time before the test, to get idle temperature (default is 15 seconds, see macoh.conf) 45 | - `-g,-gputest` - change the GpuTest type to one of: *fur*, *tess_x8*, *tess_x16*, *tess_x32*, *tess_x64*, *gi*,*pixmark_piano*, *pixmark_volplosion*, *plot3d*, *triangle* (default is *tess_x64*, see macoh.conf) 46 | - `-r,-res` - change the resolution of GpuTest (default is 1280x720, unless altered in macoh.conf) 47 | - `-m,-msaa` - change the MSAA level of GpuTest to 0 (disabled), 2, 4, or 8 (default is 2, see macoh.conf). 48 | - `-s,-gpuswitch` - force the GPU to either of: **integrated**, **discrete** or **dynamic**. You can also use **1**, **2** or **3** as synonyms. This setting only affects laptops with dual GPU (e.g. Intel Iris Pro and Nvidia). Note that this persists even after the script exits. The default setting is **dynamic** (unless you altrered it priorly) which means that the discrete GPU is in 3D. If you do not specify `-do` or `-cmd` then the script will exit after swicthing GPU (useful for scripting). 49 | 50 | #### Command line examples 51 | 52 | `macoh.sh -do x264 -wait 30` will launch the x264 transcode test with 30 seconds wait time beforehand and afterwards, downloading and installing the tools and the video as needed (skipping those already done), and generating `$HOME/macoh/${DATE}-x264.png`, `$HOME/macoh/logs/${DATE}-ipg.csv` and `$HOME/macoh/logs/${DATE}-hb.log`. 53 | 54 | `macoh.sh -do gputest -wait 10 -res 1600x900 -msaa 0 -gputest tess_x64` will launch the TessMark test from GpuTest in a 1600x900 window with MSAA disabled and a wait time beforehand and afterwards of 10 seconds. 55 | 56 | `macoh.sh -time 180 -cmd /Applications/Heaven.app/Contents/MacOS/heaven` will launch the Unigine Heaven 3D benchmark (installed separately) and will kill it after 180 seconds unless you quit it by then. You must start the Heaven benchmark manually once its app GUI opens since the script has no control over it. 57 | 58 | #### Uninstall, Folders, etc. 59 | 60 | To unistall, do: *(1)* /Applications > Intel Power Gadget > Uninstaller and *(2)* `rm -rf ~/macoh/*/*`. The latter wipes everything except generated graphs and downloaded video (note the `/*/*`). 61 | 62 | The script writes only to your home dir in `$HOME/macoh`. The only exception is Intel Power Gadget which is installed in /Applications. 63 | 64 | You can make it executable with `chmod u+x macoh.sh` and then do `./macoh.sh`. 65 | 66 | Known issues 67 | ------------ 68 | 69 | gfxCardStatus has [a bug](https://github.com/codykrieger/gfxCardStatus/issues/103), it needs somes convincing to switch the GPU. The `macoh` script makes two attempts and normally gets it. Just in case it doesn't, you may need to insist or open the app normally (via Finder/Spotlight) and switch the GPU there. 70 | 71 | Todo 72 | ---- 73 | 74 | - [ ] Fan speed monitoring +graph (any free tool?) [#2](//github.com/qnxor/macoh/issues/2) 75 | - [ ] GPU freq and temp monitoring +graph (any free tool?) [#6](//github.com/qnxor/macoh/issues/6) 76 | - [x] Add GPU testing 77 | - [x] Add Prime95 78 | - [x] Stats, Tjunction and TDP detection, etc [#3](//github.com/qnxor/macoh/issues/3) 79 | - [x] GpuTest results 80 | - [ ] Uninstall/clean option [#4](//github.com/qnxor/macoh/issues/4) 81 | - [ ] Auto-upload results and graph somewhere (with prompt)? 82 | - [ ] Cross-platform version? 83 | 84 | Credits 85 | ------- 86 | 87 | A local version of Intel Power Gadget is stored in the project for consistency. All copyright is of Intel. Binary versions of the open source applications ImageMagick, gfxCardStatus and Prime95 are also stored in the project. Using the [FFTW library](http://fftw.org) for the FFT computations. The sources of gfxCardStatus and Prime95 were modified and compiled to fit the current project. 88 | -------------------------------------------------------------------------------- /fftw/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Compile FFTW3 library MACOSX_X64 + GCC-4.9 (from Macports, port install gcc49): 4 | # 5 | # ./configure --enable-sse2 --enable-avx --enable-threads --enable-openmp 6 | # ln -s /usr/bin/clang /opt/local/bin/clang 7 | # make -j4 CFLAGS+=-Wa,-q 8 | # 9 | # You need the native clang assembler or else you can't compile the AVX 10 | # extensions ("no such instruction: ..." errors), so symlink /usr/bin/clang 11 | # into /opt/local/bin/ and then pass -Wa,-q to make's CFLAGS. 12 | 13 | cwd=`dirname $0` 14 | libgomp=/opt/local/lib/gcc49/libgomp.a 15 | 16 | # g++-mp-4.9 -O3 -fopenmp -L`dirname $0` -lgomp -lfftw3_omp -lfftw3 -o fftwtest `dirname $0`/fftwtest.cpp 17 | g++-mp-4.9 -O3 -static-libgcc -static-libstdc++ "$cwd/fftwtest.cpp" -o fftwtest \ 18 | "$libgomp" "$cwd/libfftw3_omp.a" "$cwd/libfftw3.a" 19 | 20 | # upx pack it? 21 | # download upx for mac here: http://www.idrix.fr/Root/content/category/7/26/49/ 22 | #upx -9 --lzma fftwtest 23 | -------------------------------------------------------------------------------- /fftw/fftw3.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2003, 2007-14 Matteo Frigo 3 | * Copyright (c) 2003, 2007-14 Massachusetts Institute of Technology 4 | * 5 | * The following statement of license applies *only* to this header file, 6 | * and *not* to the other files distributed with FFTW or derived therefrom: 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 20 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 23 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 25 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | /***************************** NOTE TO USERS ********************************* 33 | * 34 | * THIS IS A HEADER FILE, NOT A MANUAL 35 | * 36 | * If you want to know how to use FFTW, please read the manual, 37 | * online at http://www.fftw.org/doc/ and also included with FFTW. 38 | * For a quick start, see the manual's tutorial section. 39 | * 40 | * (Reading header files to learn how to use a library is a habit 41 | * stemming from code lacking a proper manual. Arguably, it's a 42 | * *bad* habit in most cases, because header files can contain 43 | * interfaces that are not part of the public, stable API.) 44 | * 45 | ****************************************************************************/ 46 | 47 | #ifndef FFTW3_H 48 | #define FFTW3_H 49 | 50 | #include 51 | 52 | #ifdef __cplusplus 53 | extern "C" 54 | { 55 | #endif /* __cplusplus */ 56 | 57 | /* If is included, use the C99 complex type. Otherwise 58 | define a type bit-compatible with C99 complex */ 59 | #if !defined(FFTW_NO_Complex) && defined(_Complex_I) && defined(complex) && defined(I) 60 | # define FFTW_DEFINE_COMPLEX(R, C) typedef R _Complex C 61 | #else 62 | # define FFTW_DEFINE_COMPLEX(R, C) typedef R C[2] 63 | #endif 64 | 65 | #define FFTW_CONCAT(prefix, name) prefix ## name 66 | #define FFTW_MANGLE_DOUBLE(name) FFTW_CONCAT(fftw_, name) 67 | #define FFTW_MANGLE_FLOAT(name) FFTW_CONCAT(fftwf_, name) 68 | #define FFTW_MANGLE_LONG_DOUBLE(name) FFTW_CONCAT(fftwl_, name) 69 | #define FFTW_MANGLE_QUAD(name) FFTW_CONCAT(fftwq_, name) 70 | 71 | /* IMPORTANT: for Windows compilers, you should add a line 72 | #define FFTW_DLL 73 | here and in kernel/ifftw.h if you are compiling/using FFTW as a 74 | DLL, in order to do the proper importing/exporting, or 75 | alternatively compile with -DFFTW_DLL or the equivalent 76 | command-line flag. This is not necessary under MinGW/Cygwin, where 77 | libtool does the imports/exports automatically. */ 78 | #if defined(FFTW_DLL) && (defined(_WIN32) || defined(__WIN32__)) 79 | /* annoying Windows syntax for shared-library declarations */ 80 | # if defined(COMPILING_FFTW) /* defined in api.h when compiling FFTW */ 81 | # define FFTW_EXTERN extern __declspec(dllexport) 82 | # else /* user is calling FFTW; import symbol */ 83 | # define FFTW_EXTERN extern __declspec(dllimport) 84 | # endif 85 | #else 86 | # define FFTW_EXTERN extern 87 | #endif 88 | 89 | enum fftw_r2r_kind_do_not_use_me { 90 | FFTW_R2HC=0, FFTW_HC2R=1, FFTW_DHT=2, 91 | FFTW_REDFT00=3, FFTW_REDFT01=4, FFTW_REDFT10=5, FFTW_REDFT11=6, 92 | FFTW_RODFT00=7, FFTW_RODFT01=8, FFTW_RODFT10=9, FFTW_RODFT11=10 93 | }; 94 | 95 | struct fftw_iodim_do_not_use_me { 96 | int n; /* dimension size */ 97 | int is; /* input stride */ 98 | int os; /* output stride */ 99 | }; 100 | 101 | #include /* for ptrdiff_t */ 102 | struct fftw_iodim64_do_not_use_me { 103 | ptrdiff_t n; /* dimension size */ 104 | ptrdiff_t is; /* input stride */ 105 | ptrdiff_t os; /* output stride */ 106 | }; 107 | 108 | typedef void (*fftw_write_char_func_do_not_use_me)(char c, void *); 109 | typedef int (*fftw_read_char_func_do_not_use_me)(void *); 110 | 111 | /* 112 | huge second-order macro that defines prototypes for all API 113 | functions. We expand this macro for each supported precision 114 | 115 | X: name-mangling macro 116 | R: real data type 117 | C: complex data type 118 | */ 119 | 120 | #define FFTW_DEFINE_API(X, R, C) \ 121 | \ 122 | FFTW_DEFINE_COMPLEX(R, C); \ 123 | \ 124 | typedef struct X(plan_s) *X(plan); \ 125 | \ 126 | typedef struct fftw_iodim_do_not_use_me X(iodim); \ 127 | typedef struct fftw_iodim64_do_not_use_me X(iodim64); \ 128 | \ 129 | typedef enum fftw_r2r_kind_do_not_use_me X(r2r_kind); \ 130 | \ 131 | typedef fftw_write_char_func_do_not_use_me X(write_char_func); \ 132 | typedef fftw_read_char_func_do_not_use_me X(read_char_func); \ 133 | \ 134 | FFTW_EXTERN void X(execute)(const X(plan) p); \ 135 | \ 136 | FFTW_EXTERN X(plan) X(plan_dft)(int rank, const int *n, \ 137 | C *in, C *out, int sign, unsigned flags); \ 138 | \ 139 | FFTW_EXTERN X(plan) X(plan_dft_1d)(int n, C *in, C *out, int sign, \ 140 | unsigned flags); \ 141 | FFTW_EXTERN X(plan) X(plan_dft_2d)(int n0, int n1, \ 142 | C *in, C *out, int sign, unsigned flags); \ 143 | FFTW_EXTERN X(plan) X(plan_dft_3d)(int n0, int n1, int n2, \ 144 | C *in, C *out, int sign, unsigned flags); \ 145 | \ 146 | FFTW_EXTERN X(plan) X(plan_many_dft)(int rank, const int *n, \ 147 | int howmany, \ 148 | C *in, const int *inembed, \ 149 | int istride, int idist, \ 150 | C *out, const int *onembed, \ 151 | int ostride, int odist, \ 152 | int sign, unsigned flags); \ 153 | \ 154 | FFTW_EXTERN X(plan) X(plan_guru_dft)(int rank, const X(iodim) *dims, \ 155 | int howmany_rank, \ 156 | const X(iodim) *howmany_dims, \ 157 | C *in, C *out, \ 158 | int sign, unsigned flags); \ 159 | FFTW_EXTERN X(plan) X(plan_guru_split_dft)(int rank, const X(iodim) *dims, \ 160 | int howmany_rank, \ 161 | const X(iodim) *howmany_dims, \ 162 | R *ri, R *ii, R *ro, R *io, \ 163 | unsigned flags); \ 164 | \ 165 | FFTW_EXTERN X(plan) X(plan_guru64_dft)(int rank, \ 166 | const X(iodim64) *dims, \ 167 | int howmany_rank, \ 168 | const X(iodim64) *howmany_dims, \ 169 | C *in, C *out, \ 170 | int sign, unsigned flags); \ 171 | FFTW_EXTERN X(plan) X(plan_guru64_split_dft)(int rank, \ 172 | const X(iodim64) *dims, \ 173 | int howmany_rank, \ 174 | const X(iodim64) *howmany_dims, \ 175 | R *ri, R *ii, R *ro, R *io, \ 176 | unsigned flags); \ 177 | \ 178 | FFTW_EXTERN void X(execute_dft)(const X(plan) p, C *in, C *out); \ 179 | FFTW_EXTERN void X(execute_split_dft)(const X(plan) p, R *ri, R *ii, \ 180 | R *ro, R *io); \ 181 | \ 182 | FFTW_EXTERN X(plan) X(plan_many_dft_r2c)(int rank, const int *n, \ 183 | int howmany, \ 184 | R *in, const int *inembed, \ 185 | int istride, int idist, \ 186 | C *out, const int *onembed, \ 187 | int ostride, int odist, \ 188 | unsigned flags); \ 189 | \ 190 | FFTW_EXTERN X(plan) X(plan_dft_r2c)(int rank, const int *n, \ 191 | R *in, C *out, unsigned flags); \ 192 | \ 193 | FFTW_EXTERN X(plan) X(plan_dft_r2c_1d)(int n,R *in,C *out,unsigned flags); \ 194 | FFTW_EXTERN X(plan) X(plan_dft_r2c_2d)(int n0, int n1, \ 195 | R *in, C *out, unsigned flags); \ 196 | FFTW_EXTERN X(plan) X(plan_dft_r2c_3d)(int n0, int n1, \ 197 | int n2, \ 198 | R *in, C *out, unsigned flags); \ 199 | \ 200 | \ 201 | FFTW_EXTERN X(plan) X(plan_many_dft_c2r)(int rank, const int *n, \ 202 | int howmany, \ 203 | C *in, const int *inembed, \ 204 | int istride, int idist, \ 205 | R *out, const int *onembed, \ 206 | int ostride, int odist, \ 207 | unsigned flags); \ 208 | \ 209 | FFTW_EXTERN X(plan) X(plan_dft_c2r)(int rank, const int *n, \ 210 | C *in, R *out, unsigned flags); \ 211 | \ 212 | FFTW_EXTERN X(plan) X(plan_dft_c2r_1d)(int n,C *in,R *out,unsigned flags); \ 213 | FFTW_EXTERN X(plan) X(plan_dft_c2r_2d)(int n0, int n1, \ 214 | C *in, R *out, unsigned flags); \ 215 | FFTW_EXTERN X(plan) X(plan_dft_c2r_3d)(int n0, int n1, \ 216 | int n2, \ 217 | C *in, R *out, unsigned flags); \ 218 | \ 219 | FFTW_EXTERN X(plan) X(plan_guru_dft_r2c)(int rank, const X(iodim) *dims, \ 220 | int howmany_rank, \ 221 | const X(iodim) *howmany_dims, \ 222 | R *in, C *out, \ 223 | unsigned flags); \ 224 | FFTW_EXTERN X(plan) X(plan_guru_dft_c2r)(int rank, const X(iodim) *dims, \ 225 | int howmany_rank, \ 226 | const X(iodim) *howmany_dims, \ 227 | C *in, R *out, \ 228 | unsigned flags); \ 229 | \ 230 | FFTW_EXTERN X(plan) X(plan_guru_split_dft_r2c)( \ 231 | int rank, const X(iodim) *dims, \ 232 | int howmany_rank, \ 233 | const X(iodim) *howmany_dims, \ 234 | R *in, R *ro, R *io, \ 235 | unsigned flags); \ 236 | FFTW_EXTERN X(plan) X(plan_guru_split_dft_c2r)( \ 237 | int rank, const X(iodim) *dims, \ 238 | int howmany_rank, \ 239 | const X(iodim) *howmany_dims, \ 240 | R *ri, R *ii, R *out, \ 241 | unsigned flags); \ 242 | \ 243 | FFTW_EXTERN X(plan) X(plan_guru64_dft_r2c)(int rank, \ 244 | const X(iodim64) *dims, \ 245 | int howmany_rank, \ 246 | const X(iodim64) *howmany_dims, \ 247 | R *in, C *out, \ 248 | unsigned flags); \ 249 | FFTW_EXTERN X(plan) X(plan_guru64_dft_c2r)(int rank, \ 250 | const X(iodim64) *dims, \ 251 | int howmany_rank, \ 252 | const X(iodim64) *howmany_dims, \ 253 | C *in, R *out, \ 254 | unsigned flags); \ 255 | \ 256 | FFTW_EXTERN X(plan) X(plan_guru64_split_dft_r2c)( \ 257 | int rank, const X(iodim64) *dims, \ 258 | int howmany_rank, \ 259 | const X(iodim64) *howmany_dims, \ 260 | R *in, R *ro, R *io, \ 261 | unsigned flags); \ 262 | FFTW_EXTERN X(plan) X(plan_guru64_split_dft_c2r)( \ 263 | int rank, const X(iodim64) *dims, \ 264 | int howmany_rank, \ 265 | const X(iodim64) *howmany_dims, \ 266 | R *ri, R *ii, R *out, \ 267 | unsigned flags); \ 268 | \ 269 | FFTW_EXTERN void X(execute_dft_r2c)(const X(plan) p, R *in, C *out); \ 270 | FFTW_EXTERN void X(execute_dft_c2r)(const X(plan) p, C *in, R *out); \ 271 | \ 272 | FFTW_EXTERN void X(execute_split_dft_r2c)(const X(plan) p, \ 273 | R *in, R *ro, R *io); \ 274 | FFTW_EXTERN void X(execute_split_dft_c2r)(const X(plan) p, \ 275 | R *ri, R *ii, R *out); \ 276 | \ 277 | FFTW_EXTERN X(plan) X(plan_many_r2r)(int rank, const int *n, \ 278 | int howmany, \ 279 | R *in, const int *inembed, \ 280 | int istride, int idist, \ 281 | R *out, const int *onembed, \ 282 | int ostride, int odist, \ 283 | const X(r2r_kind) *kind, unsigned flags); \ 284 | \ 285 | FFTW_EXTERN X(plan) X(plan_r2r)(int rank, const int *n, R *in, R *out, \ 286 | const X(r2r_kind) *kind, unsigned flags); \ 287 | \ 288 | FFTW_EXTERN X(plan) X(plan_r2r_1d)(int n, R *in, R *out, \ 289 | X(r2r_kind) kind, unsigned flags); \ 290 | FFTW_EXTERN X(plan) X(plan_r2r_2d)(int n0, int n1, R *in, R *out, \ 291 | X(r2r_kind) kind0, X(r2r_kind) kind1, \ 292 | unsigned flags); \ 293 | FFTW_EXTERN X(plan) X(plan_r2r_3d)(int n0, int n1, int n2, \ 294 | R *in, R *out, X(r2r_kind) kind0, \ 295 | X(r2r_kind) kind1, X(r2r_kind) kind2, \ 296 | unsigned flags); \ 297 | \ 298 | FFTW_EXTERN X(plan) X(plan_guru_r2r)(int rank, const X(iodim) *dims, \ 299 | int howmany_rank, \ 300 | const X(iodim) *howmany_dims, \ 301 | R *in, R *out, \ 302 | const X(r2r_kind) *kind, unsigned flags); \ 303 | \ 304 | FFTW_EXTERN X(plan) X(plan_guru64_r2r)(int rank, const X(iodim64) *dims, \ 305 | int howmany_rank, \ 306 | const X(iodim64) *howmany_dims, \ 307 | R *in, R *out, \ 308 | const X(r2r_kind) *kind, unsigned flags); \ 309 | \ 310 | FFTW_EXTERN void X(execute_r2r)(const X(plan) p, R *in, R *out); \ 311 | \ 312 | FFTW_EXTERN void X(destroy_plan)(X(plan) p); \ 313 | FFTW_EXTERN void X(forget_wisdom)(void); \ 314 | FFTW_EXTERN void X(cleanup)(void); \ 315 | \ 316 | FFTW_EXTERN void X(set_timelimit)(double t); \ 317 | \ 318 | FFTW_EXTERN void X(plan_with_nthreads)(int nthreads); \ 319 | FFTW_EXTERN int X(init_threads)(void); \ 320 | FFTW_EXTERN void X(cleanup_threads)(void); \ 321 | \ 322 | FFTW_EXTERN int X(export_wisdom_to_filename)(const char *filename); \ 323 | FFTW_EXTERN void X(export_wisdom_to_file)(FILE *output_file); \ 324 | FFTW_EXTERN char *X(export_wisdom_to_string)(void); \ 325 | FFTW_EXTERN void X(export_wisdom)(X(write_char_func) write_char, \ 326 | void *data); \ 327 | FFTW_EXTERN int X(import_system_wisdom)(void); \ 328 | FFTW_EXTERN int X(import_wisdom_from_filename)(const char *filename); \ 329 | FFTW_EXTERN int X(import_wisdom_from_file)(FILE *input_file); \ 330 | FFTW_EXTERN int X(import_wisdom_from_string)(const char *input_string); \ 331 | FFTW_EXTERN int X(import_wisdom)(X(read_char_func) read_char, void *data); \ 332 | \ 333 | FFTW_EXTERN void X(fprint_plan)(const X(plan) p, FILE *output_file); \ 334 | FFTW_EXTERN void X(print_plan)(const X(plan) p); \ 335 | FFTW_EXTERN char *X(sprint_plan)(const X(plan) p); \ 336 | \ 337 | FFTW_EXTERN void *X(malloc)(size_t n); \ 338 | FFTW_EXTERN R *X(alloc_real)(size_t n); \ 339 | FFTW_EXTERN C *X(alloc_complex)(size_t n); \ 340 | FFTW_EXTERN void X(free)(void *p); \ 341 | \ 342 | FFTW_EXTERN void X(flops)(const X(plan) p, \ 343 | double *add, double *mul, double *fmas); \ 344 | FFTW_EXTERN double X(estimate_cost)(const X(plan) p); \ 345 | FFTW_EXTERN double X(cost)(const X(plan) p); \ 346 | \ 347 | FFTW_EXTERN int X(alignment_of)(R *p); \ 348 | FFTW_EXTERN const char X(version)[]; \ 349 | FFTW_EXTERN const char X(cc)[]; \ 350 | FFTW_EXTERN const char X(codelet_optim)[]; 351 | 352 | 353 | /* end of FFTW_DEFINE_API macro */ 354 | 355 | FFTW_DEFINE_API(FFTW_MANGLE_DOUBLE, double, fftw_complex) 356 | FFTW_DEFINE_API(FFTW_MANGLE_FLOAT, float, fftwf_complex) 357 | FFTW_DEFINE_API(FFTW_MANGLE_LONG_DOUBLE, long double, fftwl_complex) 358 | 359 | /* __float128 (quad precision) is a gcc extension on i386, x86_64, and ia64 360 | for gcc >= 4.6 (compiled in FFTW with --enable-quad-precision) */ 361 | #if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) \ 362 | && !(defined(__ICC) || defined(__INTEL_COMPILER)) \ 363 | && (defined(__i386__) || defined(__x86_64__) || defined(__ia64__)) 364 | # if !defined(FFTW_NO_Complex) && defined(_Complex_I) && defined(complex) && defined(I) 365 | /* note: __float128 is a typedef, which is not supported with the _Complex 366 | keyword in gcc, so instead we use this ugly __attribute__ version. 367 | However, we can't simply pass the __attribute__ version to 368 | FFTW_DEFINE_API because the __attribute__ confuses gcc in pointer 369 | types. Hence redefining FFTW_DEFINE_COMPLEX. Ugh. */ 370 | # undef FFTW_DEFINE_COMPLEX 371 | # define FFTW_DEFINE_COMPLEX(R, C) typedef _Complex float __attribute__((mode(TC))) C 372 | # endif 373 | FFTW_DEFINE_API(FFTW_MANGLE_QUAD, __float128, fftwq_complex) 374 | #endif 375 | 376 | #define FFTW_FORWARD (-1) 377 | #define FFTW_BACKWARD (+1) 378 | 379 | #define FFTW_NO_TIMELIMIT (-1.0) 380 | 381 | /* documented flags */ 382 | #define FFTW_MEASURE (0U) 383 | #define FFTW_DESTROY_INPUT (1U << 0) 384 | #define FFTW_UNALIGNED (1U << 1) 385 | #define FFTW_CONSERVE_MEMORY (1U << 2) 386 | #define FFTW_EXHAUSTIVE (1U << 3) /* NO_EXHAUSTIVE is default */ 387 | #define FFTW_PRESERVE_INPUT (1U << 4) /* cancels FFTW_DESTROY_INPUT */ 388 | #define FFTW_PATIENT (1U << 5) /* IMPATIENT is default */ 389 | #define FFTW_ESTIMATE (1U << 6) 390 | #define FFTW_WISDOM_ONLY (1U << 21) 391 | 392 | /* undocumented beyond-guru flags */ 393 | #define FFTW_ESTIMATE_PATIENT (1U << 7) 394 | #define FFTW_BELIEVE_PCOST (1U << 8) 395 | #define FFTW_NO_DFT_R2HC (1U << 9) 396 | #define FFTW_NO_NONTHREADED (1U << 10) 397 | #define FFTW_NO_BUFFERING (1U << 11) 398 | #define FFTW_NO_INDIRECT_OP (1U << 12) 399 | #define FFTW_ALLOW_LARGE_GENERIC (1U << 13) /* NO_LARGE_GENERIC is default */ 400 | #define FFTW_NO_RANK_SPLITS (1U << 14) 401 | #define FFTW_NO_VRANK_SPLITS (1U << 15) 402 | #define FFTW_NO_VRECURSE (1U << 16) 403 | #define FFTW_NO_SIMD (1U << 17) 404 | #define FFTW_NO_SLOW (1U << 18) 405 | #define FFTW_NO_FIXED_RADIX_LARGE_N (1U << 19) 406 | #define FFTW_ALLOW_PRUNING (1U << 20) 407 | 408 | #ifdef __cplusplus 409 | } /* extern "C" */ 410 | #endif /* __cplusplus */ 411 | 412 | #endif /* FFTW3_H */ 413 | -------------------------------------------------------------------------------- /fftw/fftwtest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * FFTW Test part of the MacOH project 3 | * https://github.com/qnxor/macoh 4 | * 5 | * Bogdan Roman, University of Cambridge, 2015 6 | * http://www.damtp.cam.ac.uk/research/afha/bogdan 7 | */ 8 | 9 | #include 10 | #include 11 | #include "fftw3.h" 12 | #include 13 | #include 14 | 15 | void* moh_malloc(size_t n) 16 | { 17 | void* x = fftw_malloc(n); 18 | if (x) 19 | return x; 20 | else 21 | { 22 | fprintf(stderr, "Could not allocate memory. Decrease N and retry.\n"); 23 | exit(3); 24 | } 25 | } 26 | 27 | void moh_fill (double* x, int n) 28 | { 29 | for (int i = 0; i < n*n; ++i) 30 | x[i] = rand() % n*n; 31 | } 32 | 33 | void moh_fill (fftw_complex* x, int n) 34 | { 35 | for (int i = 0; i < n*n; ++i) 36 | { 37 | x[i][0] = rand() % n*n; 38 | x[i][1] = rand() % n*n; 39 | } 40 | } 41 | 42 | int main(int argc, char **argv) 43 | { 44 | if (argc < 6 || atoi(argv[1]) < 2) 45 | { 46 | printf("Syntax: %s TIME THREADS N TYPE WISDOM\n\ 47 | \n\ 48 | TIME - run for continuously for this many seconds\n\ 49 | THREADS - number of threads to use, 0 = all cores (x2 if HyperThreaded)\n\ 50 | N - generate a random N-by-N input, N must be > 1\n\ 51 | TYPE - 0=r2r, 1=r2c, 2=c2c\n\ 52 | WISDOM - 0=ESTIMATE, 1=MEASURE, 2=PATIENT, 3=EXHAUSTIVE\n\ 53 | \n\ 54 | by Bogdan Roman, University of Cambridge, 2015\n\ 55 | http://www.damtp.cam.ac.uk/research/afha/bogdan\n\ 56 | Using FFTW3 (http://fftw.org), OpenMP (http://openmp.org)\n\ 57 | ", argv[0]); 58 | exit(1); 59 | } 60 | 61 | double seconds = atof(argv[1]); 62 | int threads = atoi(argv[2]); 63 | int n = atoi(argv[3]); 64 | int type = atoi(argv[4]); 65 | int wisdom = atoi(argv[5]); 66 | int omp = threads != 1; 67 | time_t now, start = time(NULL); 68 | long count = 0; 69 | 70 | if (threads <= 0) 71 | threads = omp_get_max_threads(); 72 | 73 | fprintf(stderr, "FFTW: size=%d-by-%d, threads=%d, type=%d, wisdom=%d. Planning ...\n", 74 | seconds, n, n, threads, type, wisdom); 75 | 76 | if (omp) 77 | { 78 | fftw_init_threads(); 79 | fftw_plan_with_nthreads(threads); 80 | } 81 | 82 | switch (wisdom) 83 | { 84 | case 0: wisdom = FFTW_ESTIMATE; break; 85 | case 1: wisdom = FFTW_MEASURE; break; 86 | case 2: wisdom = FFTW_PATIENT; break; 87 | case 3: wisdom = FFTW_EXHAUSTIVE; break; 88 | default: printf("Unknown wisdom: %d\n", wisdom); exit(2); 89 | } 90 | 91 | //if (argc > 2) 92 | // fftw_import_wisdom_from_filename(argv[3]); 93 | 94 | fftw_plan p; 95 | void *x, *y; 96 | 97 | switch(type) 98 | { 99 | case 0: 100 | x = moh_malloc(n*n * sizeof(double)); 101 | y = moh_malloc(n*n * sizeof(double)); 102 | moh_fill((double*)x, n); 103 | p = fftw_plan_r2r_2d(n, n, (double*)x, (double*)y, FFTW_REDFT10, FFTW_REDFT10, wisdom); 104 | break; 105 | case 1: 106 | x = moh_malloc(n*n * sizeof(double)); 107 | y = moh_malloc(n*n * sizeof(fftw_complex)); 108 | moh_fill((double*)x, n); 109 | p = fftw_plan_dft_r2c_2d(n, n, (double*)x, (fftw_complex*)y, wisdom); 110 | break; 111 | case 2: 112 | x = moh_malloc(n*n * sizeof(fftw_complex)); 113 | y = moh_malloc(n*n * sizeof(fftw_complex)); 114 | moh_fill((fftw_complex*)x, n); 115 | p = fftw_plan_dft_2d(n, n, (fftw_complex*)x, (fftw_complex*)y, FFTW_FORWARD, wisdom); 116 | break; 117 | default: 118 | printf("Unknown type: %d\n", wisdom); exit(2); 119 | } 120 | 121 | fprintf(stderr, "FFTW: done planning in %.2f seconds. Looping for %.1f seconds ...\n", 122 | difftime(time(NULL),start), seconds); 123 | 124 | for (count = 0, start = time(NULL); difftime(time(NULL), start) < seconds; ++count) 125 | fftw_execute(p); 126 | 127 | printf("Done: %.2f ffts/sec\n", (double)count/difftime(time(NULL),start)); 128 | 129 | //if (argc > 2) 130 | // fftw_export_wisdom_to_filename("fftw.wis"); 131 | 132 | fftw_destroy_plan(p); 133 | if (omp) 134 | fftw_cleanup_threads(); 135 | fftw_free(x); 136 | fftw_free(y); 137 | } 138 | -------------------------------------------------------------------------------- /fftw/libfftw3.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qnxor/macoh/5f9195a515f04198b40b2021ca25f2caca26c054/fftw/libfftw3.a -------------------------------------------------------------------------------- /fftw/libfftw3_omp.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qnxor/macoh/5f9195a515f04198b40b2021ca25f2caca26c054/fftw/libfftw3_omp.a -------------------------------------------------------------------------------- /fftw/libfftw3_threads.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qnxor/macoh/5f9195a515f04198b40b2021ca25f2caca26c054/fftw/libfftw3_threads.a -------------------------------------------------------------------------------- /fftwtest: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qnxor/macoh/5f9195a515f04198b40b2021ca25f2caca26c054/fftwtest -------------------------------------------------------------------------------- /gfxCardStatus.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qnxor/macoh/5f9195a515f04198b40b2021ca25f2caca26c054/gfxCardStatus.tgz -------------------------------------------------------------------------------- /macoh.conf: -------------------------------------------------------------------------------- 1 | #### The working directory. 2 | # This will be used to download and place all files. Will be created if it 3 | # doesn't exist. Make surfe you have write permissions in the parent dir. 4 | home=~/macoh 5 | 6 | ### Wait time before and after the test 7 | # waitstart is used to capture idle temperature, don't set to 0. 8 | # waitend is useful to see how quickly it cools off. 9 | # Pertinent values for both: 15-30 sec. 10 | waitstart=15 # wait time before test (seconds) 11 | waitend=15 # wait time after test (seconds) 12 | 13 | ### Intel Power Gadget polling period (milliseconds) 14 | ipgpoll=500 15 | 16 | ### FFT options 17 | # Duration is in seconds 18 | fftsize=2048 # N, applies a 2D FFT on a random 2D N-by-N matrix 19 | fftduration=300 # duration (seconds) 20 | fftthreads=0 # -1 = nr of physical cores minus 1 (auto) 21 | # 0 = max threads (auto, 2xPhyCores if HyperThreaded) 22 | # n = use n > 0 threads 23 | ffttype=0 24 | fftwisdom=0 25 | 26 | ### GpuTest options 27 | # gputest can be: fur, tess_x8, tess_x16, tess_x32, tess_x64, gi, 28 | # pixmark_piano, pixmark_volplosion, plot3d, triangle. 29 | gputest=tess_x64 # see above 30 | gpumsaa=2 # 0,2,4,8 ... 0 disables MSAA 31 | gpuwidth=1280 # width (pixels) 32 | gpuheight=720 # height (pixels) 33 | gpuduration=600 # duration (seconds) 34 | 35 | ### Prime95 options 36 | # In-place FFTs are the most stressful. Larger FFTs (e.g. 128k or more) 37 | # are even more stressful. 38 | p95min=8 # Min FFT size (k) 39 | p95max=8 # Max FFT size (k) 40 | p95mem=0 # FFT memory (MB), 0 = in-place 41 | p95time=5 # time for each FFT (minutes) 42 | p95duration=300 # test duration (seconds) 43 | 44 | ### User command options 45 | # Max duration in seconds, 0=indefinte (if the user command stops by itself 46 | # then set this to either 0 or a sufficiently high value) 47 | usercmdduration=300 48 | 49 | ### Niceness (CPU priority) of FFT, HandBrake, GpuTest, Prime95. 50 | # An integer between -19 and 20. Negative values (less nice) means more CPU 51 | # priority, i.e. -19 means the highest priority (usually reserved for critical 52 | # OS processes). If you intend to run both HandBrake and GpuTest at the same 53 | # time then set both to the same nice level. 54 | # NOTE: You should *not* set this to more than 0 or else all other processes 55 | # which default to 0 will trump the stress tests which won't be able to 56 | # push the CPU as much, and result in misleading temp/freq results. 57 | # NOTE2: The Prime95 nice level is only for the master process. The child 58 | # processes are nice'd automatically. 59 | fftnice=-10 60 | hbnice=-10 61 | gpunice=-10 62 | p95nice=0 63 | 64 | ### Various 65 | # Output of HandBrake (transcoded movie). Set it to an actual file if you 66 | # want it saved (e.g. "$home/transcoded.mkv"). By default it goes into 67 | # /dev/null to avoid any disk I/O 68 | mkv=/dev/null 69 | 70 | # Quit main menu after running a test? 1=yes, 0=no 71 | menuquit=0 72 | 73 | ### URLs of the toold/content 74 | # HTTP redirects will be followed. You should NOT change these unless you 75 | # know what you're doing (useful for updates). 76 | #url_ipg="https://github.com/qnxor/macoh/raw/master/IntelPowerGadgetMac.zip" 77 | url_ipg="https://software.intel.com/file/501089/download" 78 | url_handbrake="http://download.handbrake.fr/releases/0.9.9/HandBrake-0.9.9-MacOSX.6_CLI_x86_64.dmg" 79 | url_gle="http://heanet.dl.sourceforge.net/project/glx/gle4%20(Current%20Active%20Version)/4.2.4c/gle-graphics-4.2.4c-exe-mac.dmg" 80 | url_video="http://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_1080p_h264.mov" 81 | # url_prime95="ftp://mersenne.org/gimps/p95v285.MacOSX.zip" 82 | url_prime95="https://github.com/qnxor/macoh/raw/master/mprime.tgz" 83 | url_gputest="http://www.ozone3d.net/gputest/dl/GpuTest_OSX_x64_0.7.0.zip" 84 | # Referer needed or else we get a 403 85 | url_gputest_referer="http://www.geeks3d.com/20140304/gputest-0-7-0-opengl-benchmark-win-linux-osx-new-fp64-opengl-4-test-and-online-gpu-database/" 86 | url_im="https://github.com/qnxor/macoh/raw/master/ImageMagick.tgz" 87 | url_gfx="https://github.com/qnxor/macoh/raw/master/gfxCardStatus.tgz" 88 | -------------------------------------------------------------------------------- /macoh.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # GitHub project: https://github.com/qnxor/macoh 4 | # Bogdan Roman, University of Cambridge 5 | # http://www.damtp.cam.ac.uk/research/afha/bogdan 6 | # 7 | 8 | set -e 9 | 10 | # Default vars. DO NOT CHANGE THESE. Edit macoh.conf instead. 11 | 12 | home=~/macoh 13 | usercmd='' 14 | usercmdduration=300 15 | waitstart=15 16 | waitend=15 17 | ipgpoll=500 18 | gputest=tess_x64 19 | gpuwidth=1280 20 | gpuheight=720 21 | gpumsaa=2 22 | gpuduration=600 23 | gpunice=-10 24 | p95min=8 25 | p95max=8 26 | p95mem=0 27 | p95time=5 28 | p95duration=300 29 | p95nice=0 30 | fftduration=300 31 | fftsize=2048 32 | fftthreads=-1 33 | ffttype=0 34 | fftwisdom=0 35 | fftnice=-10 36 | hbnice=-10 37 | menuquit=0 38 | mov=big_buck_bunny_1080p_h264.mov 39 | mkv=/dev/null 40 | # mkv=$home/big_buck_bunny_1080p_h264_transcoded.mkv 41 | gputesttypes='fur, tess_x8, tess_x16, tess_x32, tess_x64, gi, pixmark_piano, pixmark_volplosion, plot3d, triangle' 42 | url_ipg="https://software.intel.com/file/613985/download" 43 | url_handbrake="http://download.handbrake.fr/releases/0.9.9/HandBrake-0.9.9-MacOSX.6_CLI_x86_64.dmg" 44 | url_gle="http://heanet.dl.sourceforge.net/project/glx/gle4%20(Current%20Active%20Version)/4.2.4c/gle-graphics-4.2.4c-exe-mac.dmg" 45 | url_video="http://blender-mirror.kino3d.org/peach/bigbuckbunny_movies/big_buck_bunny_1080p_h264.mov" 46 | # url_prime95="ftp://mersenne.org/gimps/p95v285.MacOSX.zip" 47 | url_prime95="https://github.com/qnxor/macoh/raw/master/mprime.tgz" 48 | url_gputest="http://www.ozone3d.net/gputest/dl/GpuTest_OSX_x64_0.7.0.zip" 49 | url_gputest_referer="http://www.geeks3d.com/20140304/gputest-0-7-0-opengl-benchmark-win-linux-osx-new-fp64-opengl-4-test-and-online-gpu-database/" 50 | url_gfx="https://github.com/qnxor/macoh/raw/master/gfxCardStatus.tgz" 51 | url_im="http://www.imagemagick.org/download/binaries/ImageMagick-x86_64-apple-darwin13.1.0.tar.gz" 52 | 53 | 54 | #------------------------------ Core functions ------------------------------# 55 | 56 | moh-init () { 57 | # Internal vars 58 | [[ -n $1 ]] && testid=$1 || testid=`date +%Y%m%d-%H%M%S` 59 | duration=0 60 | hduration=0 61 | code='' 62 | tmp="$home/tmp" 63 | bin="$home/bin" 64 | logs="$home/logs" 65 | ipgcsv="$logs/$testid-ipg.csv" 66 | hblog="$logs/$testid-hb.log" 67 | gpucsv="$logs/$testid-gputest.csv" 68 | gpulog="$logs/$testid-gputest.log" 69 | fftlog="$logs/$testid-fft.log" 70 | # Create needed dirs 71 | mkdir -p "$home" "$logs" "$tmp" "$bin" 72 | } 73 | die () { 74 | local code=$1; shift; echo "Error: $@." >&2; exit $code 75 | } 76 | err () { 77 | local code=$1; shift; echo "Error: $@." >&2; return $code 78 | } 79 | mnt () { 80 | hdiutil attach "$1" >/dev/null 81 | } 82 | umnt () { 83 | diskutil unmount "$1" >/dev/null 84 | } 85 | wget () { 86 | curl -L -o "$@" 87 | } 88 | stddev () { 89 | # awk '{ delta = $1 - avg; avg += delta / NR; mean2 += delta * ($1 - avg); } END { print sqrt(mean2 / NR); }' 90 | awk '{sum+=$1; sumsq+=$1*$1} END {print sqrt(sumsq/NR - (sum/NR)**2)}' 91 | } 92 | mean () { 93 | awk '{ delta = $1 - avg; avg += delta / NR; } END { print avg; }' 94 | } 95 | humantime () { 96 | [[ $t -ge 86400 ]] && echo -n $(($1/86400))d 97 | [[ $1 -ge 3600 ]] && echo -n $((($1%86400)/3600))h 98 | # [[ $1 -ge 60 ]] && echo -n $((($1%3600)/60))m 99 | echo $((($1%3600)/60))m$(($1%60))s 100 | } 101 | editconf () { 102 | local val re=$' \t\n' 103 | [[ $2 =~ $re ]] && val="'$2'" || val=$2 104 | eval "$1=$val" 105 | if [[ -r "$conf" ]] && grep -qE "^$1=" "$conf"; then 106 | cp -f "$conf" "$conf~" 107 | sed -E "s:^$1=[^[:space:]]+:$1=${val//:/\\:}:" "$conf~" > "$conf" 108 | else 109 | echo "$1=$val" >> "$conf" 110 | fi 111 | } 112 | silentkill () { 113 | # Die with dignity. Kill if stubborn. 114 | # Add brackets ( ) around bg processes so we suppress "stopped" messsages 115 | ( { sleep 0.25; kill -TERM $* &>/dev/null; } & ) 116 | ( { sleep 5; kill -KILL $* &>/dev/null; } & ) 117 | # The 'wait' trick only works for subprocess of the current shell, should be fine 118 | # It suppresses the "terminated" background messages. 119 | # "wait" returns 127 if process not found (thanks!). We return 0 always. 120 | wait $* &>/dev/null || return 0 121 | } 122 | set-imagick () { 123 | local im 124 | if [[ -d $bin/ImageMagick ]]; then 125 | export MAGICK_HOME="$bin/ImageMagick" 126 | export DYLD_LIBRARY_PATH="$MAGICK_HOME/lib/" 127 | [[ "$PATH" = *"$MAGICK_HOME/bin"* ]] || export PATH="$MAGICK_HOME/bin:$PATH" 128 | fi 129 | } 130 | anykey () { 131 | local msg="Press any key to continue ..." 132 | [[ -n $1 ]] && msg="$@" 133 | echo $msg 134 | read -s -n 1 135 | } 136 | # Fetch a list of functions prefixed by PREFIX. Outputs a list separated by SEP 137 | # Usage: functionlist PREFIX SEP 138 | functionlist () { 139 | local IFS=$'\n\t ' 140 | local list=(`declare -f | grep -Eo "^$1[a-zA-Z0-9_\-]+ \(\)" | sed -E "s/^$1//;s/ \(\)//"`) 141 | list=${list[*]} 142 | echo ${list// /$2} 143 | } 144 | menu () { 145 | local i n ans map prompt=$1 default=$2 146 | local args=$@ 147 | shift 2 148 | local opts=("$@") 149 | while [[ 1 ]]; do 150 | i=0 151 | n=0 152 | map='' 153 | while [[ $i -lt $# ]]; do 154 | if [[ -z ${opts[i]} ]]; then 155 | echo 156 | else 157 | let n=n+1 158 | printf " %2d. %s\n" $n ${opts[i]} 159 | map=("${map[@]}" "${opts[i]}") 160 | fi 161 | let i=i+1 162 | done 163 | echo 164 | echo -n "$prompt" 165 | [[ -n $default ]] && echo -n " [$default] " 166 | read ans 167 | echo 168 | if [[ -z $ans ]]; then 169 | menuchoice="$default" 170 | break 171 | elif [[ $ans -ge 1 && $ans -le $n ]]; then 172 | menuchoice=${map[ans]} 173 | break 174 | else 175 | anykey "Invalid choice '$ans'. Press any key to try again ..." 176 | echo 177 | fi 178 | done 179 | } 180 | benice () { 181 | local pid 182 | echo "Changing $1's niceness to $2 ..." 183 | for ((i=0;i<120;i++)); do 184 | sleep 1 185 | pid=`pgrep $1` && { 186 | sleep 2 187 | sudo renice $2 -p $pid 188 | break 189 | } 190 | done 191 | } 192 | getfuncdef () { 193 | declare -f $1 194 | } 195 | freemb () { 196 | local IFS=$'\n\t .' 197 | local page=(`vm_stat | grep -oE "page size of [0-9]+ bytes" 2>/dev/null`) 198 | local free=(`vm_stat | grep "^Pages free:" 2>/dev/null`) 199 | IFS=$'\n\t ' 200 | page=${page[3]} 201 | free=${free[2]} 202 | [[ $page -gt 0 && $free -gt 0 ]] || { echo && return 0; } 203 | free=`echo "($page*$free)/1048576" | bc -l` 204 | echo ${free/.*/} 205 | } 206 | getphycores () { 207 | sysctl -n hw.physicalcpu 208 | } 209 | getlogicalcores () { 210 | sysctl -n hw.logicalcpu 211 | } 212 | getthreads () { 213 | if [[ $1 -lt 0 ]]; then 214 | local t=$((`getphycores`-1)) 215 | [[ $t -lt 1 ]] && echo 1 || echo $t 216 | elif [[ $1 = 0 ]]; then 217 | getlogicalcores 218 | else 219 | echo $1 220 | fi 221 | } 222 | strcmp () { 223 | [[ "$1" = "$2" ]] && return 0 || return 1 224 | } 225 | strcmpi () { 226 | shopt -s nocasematch 227 | [[ "$1" = "$2" ]] 228 | local x=$? 229 | shopt -u nocasematch 230 | return $x 231 | } 232 | regexp () { 233 | [[ "$1" =~ "$2" ]] && return 0 || return 1 234 | } 235 | regexpi () { 236 | shopt -s nocasematch 237 | [[ "$1" =~ "$2" ]] 238 | local x=$? 239 | shopt -u nocasematch 240 | return $x 241 | } 242 | 243 | #------------------------------ GET functions ------------------------------# 244 | 245 | 246 | moh-get-handbrake () 247 | { 248 | echo 249 | local ans=y 250 | # md5=d426eae09825284c8a4b66d55cafeeb4 251 | [[ -x $bin/HandBrakeCLI && $1 != force ]] && \ 252 | read -p "HandBrake CLI seems to exist in $bin. Redownload? [n] " ans 253 | if [[ $ans = y || $ans = Y ]]; then 254 | set -e 255 | rm -f $bin/done-handbrake 256 | echo Fetching HandBrake CLI into $bin ... 257 | wget $tmp/HandBrake-0.9.9-MacOSX.6_CLI_x86_64.dmg "$url_handbrake" -# 258 | mnt $tmp/HandBrake-0.9.9-MacOSX.6_CLI_x86_64.dmg 259 | cp -f /Volumes/HandBrake-0.9.9-MacOSX.6_CLI_x86_64/HandBrakeCLI $bin 260 | umnt /Volumes/HandBrake-0.9.9-MacOSX.6_CLI_x86_64 261 | > $bin/done-handbrake 262 | fi 263 | } 264 | 265 | moh-get-ipg () 266 | { 267 | echo 268 | local ans=y 269 | # md5=5e3f984efdf04fa608ef1ba35d1309fe 270 | [[ -d /Applications/Intel\ Power\ Gadget && $1 != force ]] && read -p "Intel Power Gadget seems to be installed. Redownload? [n] " ans 271 | if [[ $ans = y || $ans = Y ]]; then 272 | set -e 273 | rm -f $bin/done-ipg 274 | echo "Fetching and installing Intel Power Gadget into /Applications ..." 275 | wget $tmp/ipg.dmg "$url_ipg" -# 276 | mnt $tmp/ipg.dmg 277 | echo "Installing Intel Power Gadget may ask you to enter your Mac password." 278 | sudo installer -pkg /Volumes/Intel*\ Power\ Gadget/Install\ Intel\ Power\ Gadget.pkg -target / 279 | umnt /Volumes/Intel*\ Power\ Gadget 280 | > $bin/done-ipg 281 | fi 282 | } 283 | 284 | moh-get-gle () 285 | { 286 | echo 287 | local ans=y 288 | # md5=021e612a678cce8f2f8b1425fec1d0b5 289 | [[ -d $bin/QGLE.app && $1 != force ]] && read -p "QGLE seems to be installed. Redownload? [n] " ans 290 | if [[ $ans = y || $ans = Y ]]; then 291 | set -e 292 | rm -f $bin/done-gle 293 | echo Fetching Graphics Layout Engine into $bin ... 294 | wget $tmp/gle.dmg "$url_gle" -# 295 | mnt $tmp/gle.dmg 296 | [[ -d $bin/QGLE.app ]] && rm -rf $bin/QGLE.app 297 | cp -r /Volumes/gle-graphics-*/QGLE.app $bin 298 | umnt /Volumes/gle-graphics-* 299 | > $bin/done-gle 300 | fi 301 | } 302 | 303 | moh-get-video () 304 | { 305 | echo 306 | local ans=y 307 | # md5=c23ab2ff12023c684f46fcc02c57b585 308 | [[ -r $home/$mov && $1 != force ]] && read -p "The video file seems exist in $home. Redownload? [n] " ans 309 | if [[ $ans = y || $ans = Y ]]; then 310 | set -e 311 | rm -f $home/done-video 312 | echo "Fetching The Big Buck Bunny movie (692 MB) into $home. This may take a while ..." 313 | wget $home/$mov "$url_video" -# 314 | > $home/done-video 315 | fi 316 | } 317 | 318 | moh-get-prime95 () 319 | { 320 | echo 321 | local ans=y 322 | # md5=0390ae2ff3d4a7082927482d82e62f59 323 | [[ -x $bin/mprime && $1 != force ]] && \ 324 | read -p "Prime95 seems to be installed. Redownload? [n] " ans 325 | if [[ $ans = y || $ans = Y ]]; then 326 | set -e 327 | rm -f $bin/done-prime95 $bin/mprime 328 | echo Fetching Prime95 into $bin ... 329 | wget $tmp/mprime.tgz "$url_prime95" -# 330 | tar -C $bin -zxf $tmp/mprime.tgz 331 | > $bin/done-prime95 332 | fi 333 | } 334 | 335 | moh-get-gputest () 336 | { 337 | echo 338 | local ans=y 339 | # md5=b3dbe739f64336b1f0752149c495dbf4 340 | [[ -d $bin/GpuTest.app && $1 != force ]] && \ 341 | read -p "GpuTest seems to be installed. Redownload? [n] " ans 342 | if [[ $ans = y || $ans = Y ]]; then 343 | set -e 344 | rm -f $bin/done-gputest 345 | echo Fetching GpuTest into $bin ... 346 | wget $tmp/gputest.zip "$url_gputest" -# --referer "$url_gputest_referer" 347 | unzip -q -o $tmp/gputest.zip -d $tmp 348 | [[ -d $bin/GpuTest.app ]] && rm -rf $bin/GpuTest.app 349 | cp -rf $tmp/GpuTest.app $bin 350 | rm -rf $tmp/GpuTest.app 351 | chmod 755 $bin/GpuTest.app/Contents/MacOS/GpuTest 352 | > $bin/done-gputest 353 | fi 354 | } 355 | 356 | moh-get-gfx () 357 | { 358 | echo 359 | local ans=y 360 | # md5=1cecb1974a1d5c374dfd180a5e7b828e 361 | # [[ ( -d $bin/gfxCardStatus.app || -d /Applications/gfxCardStatus.app ) && $1 != force ]] && \ 362 | [[ -d $bin/gfxCardStatus.app && $1 != force ]] && \ 363 | read -p "gfxCardStatus seems to be installed. Redownload? [n] " ans 364 | if [[ $ans = y || $ans = Y ]]; then 365 | set -e 366 | rm -f $bin/done-gfx 367 | echo Fetching gfxCardStatus into $bin ... 368 | wget $tmp/gfxCardStatus.tgz "$url_gfx" -# 369 | [[ -d $bin/gfxCardStatus.app ]] && rm -rf $bin/gfxCardStatus.app 370 | tar -C $bin -zxf $tmp/gfxCardStatus.tgz 371 | > $bin/done-gfx 372 | fi 373 | } 374 | 375 | # Fetch and install a local copy of ImageMagick 376 | moh-get-imagick () 377 | { 378 | echo 379 | local d ans=y 380 | # md5=1cecb1974a1d5c374dfd180a5e7b828e 381 | [[ -d $bin/ImageMagick-* && $1 != force ]] && \ 382 | read -p "ImageMagick seems to be installed. Redownload? [n] " ans 383 | if [[ $ans = y || $ans = Y ]]; then 384 | set -e 385 | rm -f $bin/done-imagick 386 | echo Fetching ImageMagick into $bin ... 387 | wget $tmp/imagemagick.tgz "$url_im" -# 388 | tar -C $bin -zxf $tmp/imagemagick.tgz 389 | mv $bin/ImageMagick-* $bin/ImageMagick 390 | > $bin/done-imagick 391 | fi 392 | set-imagick 393 | } 394 | 395 | #---------------------------- DO/CHECK functions ----------------------------# 396 | 397 | # Check mandatory packages 398 | moh-check-common () { 399 | [[ -r $bin/done-ipg && -d /Applications/Intel\ Power\ Gadget ]] || moh-get-ipg force 400 | [[ -r $bin/done-gle && -d $bin/QGLE.app ]] || moh-get-gle force 401 | [[ -r $bin/done-imagick && -d $bin/ImageMagick ]] || moh-get-imagick force 402 | } 403 | 404 | # Check if all x264 test dependencies exist and download/install if not 405 | moh-check-x264 () 406 | { 407 | moh-check-common 408 | [[ -r $bin/done-handbrake && -x $bin/HandBrakeCLI ]] || moh-get-handbrake force 409 | [[ -r $home/done-video && -r $home/$mov ]] || moh-get-video force 410 | } 411 | 412 | # Check if all Prime95 test dependencies exist and download/install if not 413 | moh-check-prime95 () 414 | { 415 | moh-check-common 416 | [[ -r $bin/done-prime95 && -x $bin/mprime ]] || moh-get-prime95 force 417 | } 418 | 419 | # Check if all Prime95 test dependencies exist and download/install if not 420 | moh-check-gputest () 421 | { 422 | moh-check-common 423 | [[ -r $bin/done-gputest && -d $bin/GpuTest.app ]] || moh-get-gputest force 424 | } 425 | 426 | # Check packages for the FFT test 427 | moh-check-fft () 428 | { 429 | moh-check-common 430 | } 431 | 432 | # Check packages for a user defined command 433 | moh-check-usercmd () 434 | { 435 | moh-check-common 436 | } 437 | 438 | # Check packages for a user defined command 439 | moh-check-gfx () 440 | { 441 | [[ -r $bin/done-gfx && -d $bin/gfxCardStatus.app ]] || moh-get-gfx force 442 | } 443 | 444 | ## Start any user specified command and log it (it must terminate) 445 | ## TODO: add timer 446 | moh-cmd () 447 | { 448 | do=usercmd 449 | moh-check-usercmd 450 | echo "$usercmd" | moh-wrapper UserCmd $usercmdduration 451 | } 452 | 453 | ## Do my FFTW test 454 | moh-do-fft () 455 | { 456 | do=fft 457 | moh-check-fft 458 | local cmd="$(dirname $0)/fftwtest" 459 | local threads=`getthreads $fftthreads` 460 | chmod +x "$cmd" 461 | moh-wrapper FFT <<-SH 462 | echo 463 | sudo nice -n $fftnice "$cmd" $fftduration $threads $fftsize $ffttype $fftwisdom 2>&1 | tee $fftlog 464 | echo 465 | SH 466 | } 467 | 468 | # Run GpuTest 469 | moh-do-gputest () 470 | { 471 | do=gputest 472 | moh-check-gputest 473 | local sudo 474 | [[ $gpunice -lt 0 ]] && sudo=sudo 475 | moh-wrapper GpuTest <<-SH 476 | $(getfuncdef benice) 477 | benice GpuTest $gpunice & 478 | $bin/GpuTest.app/Contents/MacOS/GpuTest '/test=$gputest /width=$gpuwidth /height=$gpuheight /msaa=$gpumsaa /benchmark /benchmark_duration_ms=${gpuduration}000 /no_scorebox' &>/dev/null 479 | SH 480 | } 481 | 482 | # Run Prime95 ... currently buggy, torture test does not always start with -t 483 | # http://www.mersenneforum.org/showthread.php?p=372979#post372918 484 | moh-do-prime95 () 485 | { 486 | do=prime95 487 | moh-check-prime95 488 | 489 | # local workdir=~/Prime95 490 | # [[ -d $workdir ]] && rm -rf $workdir 491 | # mkdir -p $workdir 492 | 493 | # cat <<-STR 494 | 495 | # --------------- 496 | # W A R N I N G 497 | # --------------- 498 | 499 | # There is a bug in Prime95, the torture test does not start automatically when the GUI opens. For now, do it manually once the GUI opens as follows: 500 | 501 | # Options -> Torture Test -> Custom -> MinFFT=$p95min, MaxFFT=$p95max, Memory=$p95mem, Time=$p95time -> Run. 502 | 503 | # Press any key to start Prime95 ... 504 | 505 | # STR 506 | # read -s -n 1 507 | 508 | # Small in-place: Min=8,Max=8,Mem=8 (in-place when TortureMem = 0) 509 | # Large in-place: Min=128,Max=1024,Mem=8 (in-place when TortureMem = 0) 510 | # Blend: Min=8, Max=1792, Mem=2048 511 | # For small with some mem: Min=8, Max=16, Mem=512, Time=5 512 | cat > $bin/prime.txt <<-TXT 513 | V24OptionsConverted=1 514 | WGUID_version=2 515 | StressTester=1 516 | UsePrimenet=0 517 | MinTortureFFT=$p95min 518 | MaxTortureFFT=$p95max 519 | TortureMem=$p95mem 520 | TortureTime=$p95time 521 | Nice=$p95nice 522 | 523 | [PrimeNet] 524 | Debug=0 525 | TXT 526 | # ManualComm=1 527 | # SumInputsErrorCheck=0 528 | # ErrorCheck=0 529 | # StaggerStarts=1 530 | # MergeWindows=12 531 | # NoMoreWork=0 532 | 533 | moh-wrapper Prime95 $p95duration <<-SH 534 | echo 535 | # $bin/mprime -t -W$bin | sed -E '/Please read|Beginning a|Worker starting|Setting affinity/d' 536 | $bin/mprime -t -W$bin 537 | echo 538 | SH 539 | } 540 | 541 | ## Start the normal x264 test 542 | moh-do-x264 () { 543 | do=x264 544 | moh-check-x264 545 | # HandBrake changes its nice level to 19 after it starts so we can't start 546 | # it with nice -n 0 HandBrakeCLI. Prepend a background process to poll for 547 | # it and renice it once detected 548 | # NOTE: starting with nice is not a good idea since negative values require 549 | # sudo which then causes HB to place the log files in /root ... 550 | moh-wrapper x264 <<-SH 551 | $(getfuncdef benice) 552 | benice HandBrakeCLI $hbnice & 553 | $bin/HandBrakeCLI -i $home/$mov -o $mkv -f mkv -4 -w 1280 -l 720 -e x264 -q 26 --vfr -a 1 -E ffaac -B 128 -6 stereo -R Auto -D 0 --gain=0 --audio-copy-mask none --audio-fallback ffaac -x rc-lookahead=50:ref=8:bframes=16:me=umh:subme=9:merange=24 --verbose=1 2>$hblog 554 | SH 555 | } 556 | 557 | ## Start the long x264 test 558 | moh-do-x264-long () { 559 | do=x264-long 560 | moh-check-x264 561 | moh-wrapper x264-Long <<-SH 562 | $(getfuncdef benice) 563 | benice HandBrakeCLI $hbnice & 564 | # $bin/HandBrakeCLI -i $home/$mov -o $mkv -f mkv -4 -w 1280 -l 720 -e x264 -q 20 --vfr -a 1 -E ffaac -B 128 -6 stereo -R Auto -D 0 --gain=0 --audio-copy-mask none --audio-fallback ffaac -x rc-lookahead=50:ref=16:bframes=16:b-adapt=2:direct=auto:me=tesa:subme=11:merange=48:analyse=all:trellis=2 --verbose=1 2>$hblog 565 | # $bin/HandBrakeCLI -i $home/$mov -o $mkv -f mkv -4 -w 1280 -l 720 -e x264 -q 20 --vfr -a 1 -E ffaac -B 128 -6 stereo -R Auto -D 0 --gain=0 --audio-copy-mask none --audio-fallback ffaac --x264-preset=veryslow --verbose=1 2>$hblog 566 | $bin/HandBrakeCLI -i $home/$mov -o $mkv -f mkv -4 -w 1280 -l 720 -e x264 -q 26 --vfr -a 1 -E ffaac -B 128 -6 stereo -R Auto -D 0 --gain=0 --audio-copy-mask none --audio-fallback ffaac -x rc-lookahead=200:ref=16:bframes=16:b-adapt=2:direct=auto:me=esa:subme=9:merange=24 --verbose=1 2>$hblog 567 | SH 568 | } 569 | 570 | moh-do-gfx () { 571 | do=gfx 572 | open "$bin/gfxCardStatus.app" 573 | echo "gfxCardStatus started, it should appear on the menu bar. Click it to select which GPU to use for 3D if you have both an integrated and discrete GPU." 574 | } 575 | 576 | moh-do-plot () { 577 | do=plot 578 | moh-plot $testid 579 | } 580 | 581 | #--------------------------- AUXILIARY functions ---------------------------# 582 | 583 | moh-gpudetect () { 584 | moh-check-gfx 585 | local i j log pid 586 | $bin/gfxCardStatus.app/Contents/MacOS/gfxCardStatus &> $tmp/gfx.log & 587 | pid=$! 588 | echo Detecting GPUs ... 589 | for ((i=0;i<10;i++)); do 590 | sleep 1 591 | log=$(<$tmp/gfx.log) 592 | if [[ "$log" =~ GPUs\ present:\ \([^\)]+$'\n'\) ]]; then 593 | log=${log/*GPUs present: (/} 594 | log=${log/)*/} 595 | log="${log//[\",]/}" 596 | local IFS=$'\n' 597 | log=($log) 598 | local IFS=$'\n\t ' 599 | if [[ ${#log[*]} -lt 2 ]]; then 600 | silentkill $pid 601 | echo "Only one GPU detected. Nothing to switch. Exiting ..." >&2 602 | return 15 603 | else 604 | # for ((j=0;j<${#log[*]};j++)); do echo $((j+1)). ${log[j]}; done 605 | silentkill $pid 606 | return 0 607 | fi 608 | fi 609 | done 610 | silentkill $pid 611 | echo Timeout waiting for gfxCardStatus. >&2 612 | return 16 613 | } 614 | 615 | # moh-gpuswitch MODE, where MODE={1,2,3} for integrated, discrete, dynamic 616 | moh-gpuswitch () { 617 | moh-check-gfx 618 | moh-gpudetect || return $? 619 | local i j log pid arg n=2 name=$1 line readouts finished size logfile=$logs/gfx.log 620 | arg=`echo $1 | tr '[:upper:]' '[:lower:]'` 621 | [[ $1 = 1 ]] && arg=integrated && name=Integrated 622 | [[ $1 = 2 ]] && arg=discrete && name=Discrete 623 | [[ $1 = 3 ]] && arg=dynamic && name=Dynamic 624 | [[ $arg =~ ^integrated|discrete|dynamic$ ]] \ 625 | || die $ERR_GPUSWITCH "Invalid GPU switch parameter '$arg'. GPU not switched." 626 | echo Switching GPU to $name ... 627 | # Need to attempt 2-3 times due to a bug 628 | # https://github.com/codykrieger/gfxCardStatus/issues/103 629 | for ((i=1;i<=n;i++)); do 630 | echo Pass $i/$n ... 631 | # It also doesn't exit, so we need to background it, monitor its log file, then kill it ... 632 | > $logfile 633 | $bin/gfxCardStatus.app/Contents/MacOS/gfxCardStatus --$arg &> $logfile & 634 | pid=$! 635 | # stop when file size stops increasing 636 | for ((j=0;j<10;j++)); do 637 | [[ $j = 0 ]] && sleep 1 || sleep 1 638 | size[1]=`wc -c $logfile` 639 | [[ ${size[0]} = ${size[1]} ]] && break 640 | size[0]=${size[1]} 641 | # for ((j=0;j&2 && return $ERR_GPUSWITCH 650 | # echo killing pid=$pid $i 651 | silentkill $pid 652 | done 653 | echo "Done. GPU should now be switched to $name. " 654 | } 655 | 656 | moh-gpuswitch-menu () { 657 | moh-check-gfx 658 | moh-gpudetect || return $? 659 | echo 660 | menu "Choose GPU:" Abort Integrated Discrete Dynamic "" Abort 661 | [[ $menuchoice = Abort ]] && return 0 662 | moh-gpuswitch $menuchoice 663 | anykey 664 | } 665 | 666 | ## Parse Prime95 log and populate the global $duration, $mins, $secs, $perf 667 | ## For now it does nothing since Prime95 is killed forcefully as it lacks a 668 | ## stop condition 669 | moh-perf-prime95 () { 670 | perf="min:$p95min, max:$p95max, mem:$p95mem, time:$p95time" 671 | testname=Prime95 672 | } 673 | 674 | ## Parse HandBrake log and populate the global $duration, $mins, $secs, $perf 675 | moh-perf-x264 () { 676 | [[ -r $hblog ]] || return 0 677 | local frames=(`grep -Eo 'got [0-9]+ frames' $hblog`) 678 | frames=${frames[1]} 679 | local fps=(`grep -Eo 'average encoding speed for job is [0-9.]+ fps' $hblog`) 680 | fps=${fps[6]} 681 | duration=`echo "$frames/$fps" | bc -l` 682 | duration=${duration/.*/} 683 | hduration=`humantime $duration` 684 | perf="${fps:0:5} fps" 685 | testname=x264 686 | } 687 | 688 | moh-perf-x264-long () { 689 | moh-perf-x264 690 | testname=x264-Long 691 | } 692 | 693 | ## Populate the graph title for the FFTW test 694 | moh-perf-fft () { 695 | local ffts 696 | [[ -r $fftlog ]] && ffts=`grep -Eo "[0-9.]+ ffts/sec" $fftlog` 697 | perf="threads:$(getthreads $fftthreads), size:$fftsize, type:$ffttype, wisdom:$fftwisdom" 698 | [[ -n $ffts ]] && perf="$perf, $ffts" 699 | testname=FFT 700 | } 701 | 702 | ## Parse GpuTest log and populate the global $duration, $mins, $secs, $perf 703 | moh-perf-gputest () { 704 | [[ -r $gpucsv ]] || return 0 705 | local IFS=$'\n\t,' 706 | local csv=($(<$gpucsv)) 707 | local IFS=$'\n\t ' 708 | local n=${#csv[*]} 709 | local frames=${csv[n-1]} 710 | duration=$((csv[n-3]/1000)) 711 | hduration=`humantime $duration` 712 | local gpu=${csv[n-10]} 713 | gpu=${gpu/ OpenGL Engine/} 714 | gpu=${gpu/NVIDIA/Nvidia} 715 | gpu=${gpu/GeForce /} 716 | local fps=`echo "$frames/$duration" | bc -l` 717 | perf="${fps:0:5} fps, ${gpuwidth}x$gpuheight, ${gpumsaa}xAA, $gpu" 718 | testname=GpuTest 719 | } 720 | 721 | ## Wrapper to start, monitor and log any job which is read from stdin 722 | ## usage wrapper NAME TIMEOUT 723 | ## - NAME is a short no-spaces name of the job, e.g. x264-long 724 | ## - TIMEOUT is a duration in seconds after which the test is forcefully killed 725 | ## Use 0 to disable the timeout. 726 | moh-wrapper () 727 | { 728 | echo 729 | 730 | # set test name (displayed in the graph title) 731 | local testname=$1 732 | 733 | # Prepare script file to pass to Intel Power Gadget 734 | local cmdfile=$tmp/cmd-$do.sh 735 | 736 | local code=$(/dev/null & } && kill -TERM $pids; ) &>/dev/null & 750 | # ( { sleep '$2'; pids=`pgrep -P $$ 2>/dev/null` && silentkill $pids; } & ) 751 | ' 752 | 753 | # Is the code using sudo? If so, ask for the password now to avoid the 754 | # password prompt being ocluded later by the wrapping scripts which may 755 | # redirect stdout/stderr. 756 | local needsudo=`sudo -n echo foo 2>/dev/null` 757 | [[ $code =~ sudo && $needsudo != foo ]] && { 758 | echo Your password is needed to run the test in elevated mode. 759 | sudo echo 760 | } 761 | 762 | # Build script file to pass to Intel Power Gadget 763 | cat > $cmdfile <<-SH 764 | #!/bin/bash 765 | { 766 | echo Waiting $waitstart seconds to capture idle temperature ... 767 | sleep $waitstart 768 | echo Starting $testname benchmark. It may take a while and fans may go berserk ... 769 | $watchdog 770 | $code 771 | echo Test finished. Cooling off for $waitend seconds ... 772 | sleep $waitend 773 | } >&2 774 | SH 775 | chmod 700 $cmdfile 776 | 777 | # Finally ... Go! 778 | local timestart=$(date +%s) 779 | > $tmp/ipgvals.log 780 | #script -q /dev/null \ 781 | /Applications/Intel\ Power\ Gadget/PowerLog -resolution $ipgpoll \ 782 | -file $ipgcsv -cmd $cmdfile > $tmp/ipgvals.log 783 | local timeend=$(date +%s) 784 | 785 | # Don't do these in $code because the user may press Ctrl-C 786 | [[ $do =~ gputest ]] && { 787 | [[ -r ~/_geeks3d_gputest_log.txt ]] && mv ~/_geeks3d_gputest_log.txt $gpulog 788 | [[ -r ~/_geeks3d_gputest_scores.csv ]] && mv ~/_geeks3d_gputest_scores.csv $gpucsv 789 | } 790 | 791 | # Populate the global $duration, $mins, $secs 792 | duration=$((timeend-timestart-waitstart-waitend)) 793 | hduration=`humantime $duration` 794 | 795 | # Plot result 796 | moh-plot $testname 797 | } 798 | 799 | # Plot 800 | moh-plot () { 801 | local testname=$1 802 | 803 | # Prepare to plot graph from the csv output of IPG 804 | cat >$tmp/ipg.gle <<-'GLE' 805 | papersize 20 10 806 | size 20 10 807 | !margins 2 2 2 2 808 | set font texcmss 809 | set titlescale 1 810 | !set texlabels 1 811 | Tmax = arg(6) 812 | Tmax2 = 0.95*Tmax 813 | TDP = arg(7) 814 | begin graph 815 | title arg$(2) dist 0.5 816 | xtitle "Time (sec)" 817 | x2axis off 818 | y2title "CPU Frequency (MHz)" color blue 819 | ! y2side color blue 820 | axis grid 821 | subticks on 822 | ticks color rgb255(224,224,224) 823 | subticks lstyle 2 824 | subticks color rgb255(224,224,224) 825 | yaxis min 0 max 120 dticks 10 dsubticks 3.3333 826 | y2axis min 400 max 4000 dticks 300 ftick 400 827 | ! xnames from d1 828 | ! key pos bl nobox offset 2.5 0.25 829 | data arg$(1) ignore 1 d1=c1,c9 d2=c1,c2 d3=c1,c3 830 | ! d1 line color red key arg$(3) 831 | ! d2 x2axis y2axis line color !blue key ""+arg$(5)+"" 832 | ! d3 line color green key arg$(4) 833 | d1 line color red 834 | d2 x2axis y2axis line color blue 835 | d3 line color green 836 | let d4 = Tmax 837 | !let d5 = Tmax2 838 | let d6 = TDP 839 | d4 lstyle 2 color red 840 | !d5 lstyle 2 color red 841 | d6 lstyle 2 color green 842 | end graph 843 | 844 | begin key 845 | position bl 846 | !nobox 847 | offset 2.5 0.25 848 | line color red text arg$(3) 849 | line color blue text arg$(5) 850 | line color green text arg$(4) 851 | end key 852 | 853 | ! Left axis labels, we want multiple colors so we 854 | ! use tex instead of ytitle 855 | 856 | amove xg(xgmax/100) yg(Tmax+1) 857 | set color red 858 | write "Tmax="+format$(Tmax,"fix 1")+"C" 859 | 860 | !amove xg(xgmax/100) yg(Tmax2+1) 861 | !set color red 862 | !tex "0.95 Tmax" name tmax2 863 | 864 | amove xg(xgmax/100) yg(TDP+1) 865 | set color green 866 | write "TDP="+format$(TDP,"fix 1")+"W" 867 | 868 | amove 2.1 2.25 869 | set color green 870 | begin rotate 90 871 | write "CPU Power (W)" 872 | end rotate 873 | 874 | amove 2.1 4.9 875 | set color black 876 | begin rotate 90 877 | write "," 878 | end rotate 879 | 880 | amove 2.1 5.25 881 | set color red 882 | begin rotate 90 883 | write "CPU Temp (C)" 884 | end rotate 885 | GLE 886 | 887 | # graph files 888 | local graph=$home/$testid-$do.png 889 | local graphgif=$home/$testid-$do.gif 890 | 891 | # Read TDP from igp's report ... need to log stderr for that 892 | #TODO: log IGP stderr too 893 | 894 | # Remove the 11 trailing lines (Intel decided to add non-csv at athe end) 895 | # and the first two columns (there's a bug in GLE: it can't properly read 896 | # the xnames from a column different than 1st column; 897 | # "xnames from d1" reads the y values, instead of x values) 898 | local lines=(`wc -l "$ipgcsv"`) 899 | head -n $((${lines[0]}-11)) $ipgcsv | sed 's/^[^,]*,[^,]*,//' > $tmp/ipg.csv 900 | lines=(`wc -l $tmp/ipg.csv`) 901 | 902 | # Get max temp, max freq, duration and avg fps 903 | local maxtemp=`cut -f9 -d, $tmp/ipg.csv | sed 's/[[:space:]]//g' | sort -n | tail -1` 904 | local maxpow=`cut -f3 -d, $tmp/ipg.csv | sed 's/[[:space:]]//g' | sort -n | tail -1` 905 | local maxfreq=`cut -f2 -d, $tmp/ipg.csv | sed 's/[[:space:]]//g' | sort -n | tail -1` 906 | printf -v maxpow "%.1f" $maxpow 907 | 908 | # get TDP and Tmax 909 | local Tmax=`grep -oE '^Max Temp = [0-9.]+' $tmp/ipgvals.log` 910 | Tmax=${Tmax##* } 911 | [[ -n $Tmax ]] || Tmax=0 912 | local TDP=`grep -oE '^TDP.*= [0-9.]+' $tmp/ipgvals.log` 913 | TDP=${TDP##* } 914 | [[ -n $TDP ]] || TDP=0 915 | 916 | # idle period lines in the csv (skip these to compute avg,std) 917 | local linestart=$(((waitstart+2)*1000/ipgpoll)) 918 | local lineend=$((lines-(waitend+2)*1000/ipgpoll)) 919 | local readuseful="sed -n ${linestart},${lineend}p $tmp/ipg.csv" 920 | 921 | # Get mean and stddev for temp 922 | local avgfreq=`$readuseful | awk -F',' '{s+=$2} END {printf "%.0f\n", s/NR}'` 923 | local avgpow=`$readuseful | awk -F',' '{s+=$3} END {printf "%.1f\n", s/NR}'` 924 | local avgtemp=`$readuseful | awk -F',' '{s+=$9} END {printf "%.1f\n", s/NR}'` 925 | local stdfreq=`$readuseful | awk -F',' '{d=$2-'$avgfreq';s+=d*d} END {printf "%.0f\n", sqrt(s/NR)}'` 926 | local stdpow=`$readuseful | awk -F',' '{d=$3-'$avgpow';s+=d*d} END {printf "%.1f\n", sqrt(s/NR)}'` 927 | local stdtemp=`$readuseful | awk -F',' '{d=$9-'$avgtemp';s+=d*d} END {printf "%.1f\n", sqrt(s/NR)}'` 928 | 929 | # compute how much the Temp and Power are >= the limits 930 | local overlimpow=`$readuseful | awk -F',' '$3 > '$TDP' {s+=1} END {printf "%.1f%%\n", s/NR*100}'` 931 | local overlimtemp=`$readuseful | awk -F',' '$9 > 0.95*'$Tmax' {s+=1} END {printf "%.1f%%\n", s/NR*100}'` 932 | 933 | # Parse log files and extract perf and duration strings 934 | moh-perf-$do 935 | # Extract duration if it wasn't set in moh-perf-$do 936 | [[ -z $duration || $duration = 0 ]] && { 937 | duration=`cut -f1 -d, $tmp/ipg.csv | tail -n 1` 938 | printf -v duration "%.0f" $duration 939 | let duration=duration-waitstart-waitend 940 | hduration=`humantime $duration` 941 | } 942 | 943 | # Prepend to title, $testname shoul dbe set in moh-perf-$do (or before) 944 | local testtitle=$testname 945 | [[ $do = gputest ]] && testtitle="$testtitle ($gputest)" 946 | 947 | # CPU model 948 | local cpu=`sysctl -n machdep.cpu.brand_string` 949 | cpu=${cpu/ CPU/} 950 | cpu=${cpu/(TM)/} 951 | cpu=${cpu/(R)/} 952 | cpu=${cpu/Intel /} 953 | cpu=${cpu/AMD /} 954 | 955 | # Graph title 956 | local graphtitle="$testtitle - $cpu - $hduration" 957 | [[ -n $perf ]] && graphtitle="$graphtitle, $perf" 958 | 959 | # Plot graph, -resolution sets the DPI, note that the PNG driver is 960 | # a rasterized and resampled version of the internal Postscript output, and 961 | # as such, the values sometimes may appear slightly off due to resampling 962 | $bin/QGLE.app/Contents/bin/gle -cairo -resolution 200 -d png -verbosity 0 \ 963 | -output $graph \ 964 | $tmp/ipg.gle \ 965 | $tmp/ipg.csv \ 966 | "$graphtitle" \ 967 | "Temp, max:${maxtemp}, avg:${avgtemp}, above 0.95Tmax:${overlimtemp}" \ 968 | "Power, max:${maxpow}, avg:${avgpow}, above TDP:${overlimpow}" \ 969 | "Freq, max:${maxfreq}, avg:${avgfreq}" \ 970 | $Tmax \ 971 | $TDP \ 972 | >/dev/null 973 | 974 | # Crop and make smaller, use sips if ImageMagick is not available 975 | set-imagick 976 | if which convert &>/dev/null; then 977 | rm -f $graph-1 978 | mogrify -crop 1340x730+125+35 -quality 96 -colors 64 -write $graph-1 $graph \ 979 | && mv $graph-1 $graph 980 | elif which sips &>/dev/null; then 981 | sips -s format gif $graph --out $graphgif &>/dev/null 982 | graph=$graphgif 983 | rm $graph 984 | fi 985 | rm -f $graph*~ 986 | 987 | echo 988 | [[ -n $perf ]] && echo "Benchmark: $perf" 989 | cat <<-STR 990 | Max temp reached: $maxtemp C 991 | Test duration: $duration secs ($hduration) 992 | 993 | See $graph for the full graph. 994 | 995 | STR 996 | 997 | # open graph 998 | open $graph 999 | } 1000 | 1001 | 1002 | #--------------------------------- SCRIPT ---------------------------------# 1003 | 1004 | 1005 | # Error codes 1006 | ERR_CMDLINE=11 1007 | ERR_KILL=13 1008 | ERR_GPUSWITCH=19 1009 | 1010 | 1011 | # Parse conf file. Overrides defaults, but not cmd line options. 1012 | conf="$(dirname $0)/macoh.conf" 1013 | [[ -r "$conf" ]] && source "$conf" 1014 | 1015 | # Parse cmd line args (hack job, I know, will use getopts() later) 1016 | while [[ -n $@ ]]; do 1017 | [[ $1 = -c || $1 = -cmd ]] && shift && usercmd="$@" && break # -cmd must be the last option 1018 | [[ $1 = -w || $1 = -wait ]] && waitstart=$2 && waitend=$2 && shift 2 && continue 1019 | [[ $1 = -t || $1 = -time ]] && timeout=${2:-0} && shift 2 && continue 1020 | [[ $1 = -do ]] && do=$2 && shift 2 && continue 1021 | [[ $1 = -get ]] && get=$2 && shift 2 && continue 1022 | [[ $1 = -r || $1 = -res ]] && gpuwidth=${2/x*/} && gpuwidth=${2/*x/} && shift 2 && continue 1023 | [[ $1 = -m || $1 = -msaa ]] && gpumsaaa=$2 && shift 2 && continue 1024 | [[ $1 = -s || $1 = -gpuswitch ]] && gpuswitch=$2 && shift 2 && continue 1025 | [[ $1 = -g || $1 = -gputest ]] && gputest=$2 && shift 2 && continue 1026 | [[ $1 = -name ]] && testname=$2 && shift 2 && continue 1027 | [[ $1 = -plot ]] && { 1028 | testid=`basename ${2%.*}` 1029 | [[ $testid == *-*-* ]] || die $ERR_CMDLINE "-plot requires a filename YYYYMMDD-HHMMSS-NAME.log" 1030 | do=${testid#*-*-} 1031 | testid=${testid%-*} 1032 | justplot=1 1033 | shift 2 1034 | continue 1035 | } 1036 | die $ERR_CMDLINE "Unrecognized option '$1'" 1037 | done 1038 | 1039 | # init variables 1040 | moh-init $testid 1041 | 1042 | # Validate inputs / conf 1043 | 1044 | [[ $waitstart -gt 0 && $waitend -gt 0 ]] || die $ERR_CMDLINE "-w/-wait requires a positive integer" 1045 | [[ $gpuwidth -gt 0 && $gpuheight -gt 0 ]] || die $ERR_CMDLINE "-r/-res requires MxM, where M and N are positive integers" 1046 | [[ $gpumsaa = [0248] ]] || die $ERR_CMDLINE "-m/-msaa requires 0, 2, 4 or 8" 1047 | [[ $timeout -ge 0 ]] || die $ERR_CMDLINE "-t/-time requires a non-negative integer" 1048 | [[ ", $gputesttypes, " = *", $gputest, "* ]] || die $ERR_CMDLINE "-g/-gputest requires one of: $gputesttypes" 1049 | 1050 | # Cmd line GPU switch? 1051 | [[ -n $gpuswitch ]] && case $gpuswitch in 1052 | integrated) moh-gpuswitch 1; ecode=$?;; 1053 | discrete) moh-gpuswitch 2; ecode=$?;; 1054 | dynamic) moh-gpuswitch 3; ecode=$?;; 1055 | [012]) moh-gpuswitch $gpuswitch; ecode=$?;; 1056 | *) die $ERR_CMDLINE "-s/-gpuswitch requires one of: integrated, discrete, dynamic or 0, 1, 2" 1057 | esac 1058 | 1059 | [[ -n $justplot ]] && { 1060 | moh-plot $testid 1061 | exit $? 1062 | } 1063 | 1064 | # Cmd line predefined test? 1065 | [[ -n $do ]] && { 1066 | dolist=$(functionlist "moh-do-" ", ") 1067 | dore=$(functionlist "moh-do-" "|") 1068 | [[ $do =~ ^$dore$ ]] || die $ERR_CMDLINE "-do requires one of: $dolist" 1069 | [[ $do = gputest && -n $timeout ]] && gpuduration=$timeout 1070 | [[ $do = prime95 && -n $timeout ]] && p95duration=$timeout 1071 | moh-do-$do 1072 | exit $? 1073 | } 1074 | 1075 | # Cmd line fetch? 1076 | [[ -n $get ]] && { 1077 | getlist=$(functionlist "moh-get-" ", ") 1078 | getre=$(functionlist "moh-get-" "|") 1079 | [[ $get =~ ^$re$ ]] || die $ERR_CMDLINE "-get requires one of: $getlist" 1080 | moh-get-$get 1081 | exit $? 1082 | } 1083 | 1084 | # Cmd line user command? 1085 | [[ -n $usercmd ]] && { 1086 | [[ $timeout -ge 0 ]] && usercmdduration=$timeout 1087 | moh-cmd 1088 | exit $? 1089 | } 1090 | 1091 | # If only the -g/-gpuswitch was used, exit (allows scripting) 1092 | [[ -n $gpuswitch ]] && exit $ecode 1093 | 1094 | # If not, show menu 1095 | while [[ 1 ]] 1096 | do 1097 | # call this here to re-init testid and filename (date/time) or else 1098 | # tests will override each other if the user does not exit the menu 1099 | moh-init 1100 | 1101 | s_hbnice=`printf '%-5s' "[$hbnice]"` 1102 | s_gpunice=`printf '%-5s' "[$gpunice]"` 1103 | s_p95dur=`printf '%-10s' "[$(humantime $p95duration)]"` 1104 | s_gpudur=`printf '%-10s' "[$(humantime $gpuduration)]"` 1105 | s_res=`printf '%-11s' "[${gpuwidth}x$gpuheight]"` 1106 | s_p95min=`printf '%-8s' "[${p95min}k]"` 1107 | s_p95max=`printf '%-8s' "[${p95max}k]"` 1108 | s_fftsize=`printf '%-8s' "[$fftsize]"` 1109 | s_fftthreads=`printf '%-8s' "[$(getthreads $fftthreads)]"` 1110 | s_fftdur=`printf '%-10s' "[$(humantime $fftduration)]"` 1111 | [[ $p95mem = 0 ]] && s_p95mem='[in-place]' || s_p95mem=`printf '%-10s' "[${p95mem}MB]"` 1112 | s_p95time=`printf '%-8s' "[${p95time}m]"` 1113 | 1114 | echo -n " 1115 | ----------------------------------------------------------------------------- 1116 | MacOH v1.5.4. Quit all other apps before launching. 1117 | ----------------------------------------------------------------------- TESTS 1118 | F. FFT multi-threaded (+ CPU stress) 1119 | X. Short x264 encode (++ CPU stress, 5-6 mins on Core i7-4850HQ) 1120 | Y. Long x264 encode (++ CPU stress, about 4 times longer) 1121 | P. Prime95 (++++ CPU stress, expect laptops to throttle) 1122 | G. 3D GpuTest (also try switching GPU beforehand) 1123 | S. Switch GPU to integrated or discrete 1124 | --------------------------------------------------------------------- OPTIONS 1125 | FD. FFT duration $s_fftdur PD. Prime95 duration $s_p95dur 1126 | FT. FFT threads $s_fftthreads PM. Prime95 memory $s_p95mem 1127 | FS. FFT size $s_fftsize PS. Prime95 fft min,max [${p95min}k,${p95max}k] 1128 | GD. GpuTest duration $s_gpudur GM. GpuTest MSAA [$gpumsaa] 1129 | GR. GpuTest res $s_res GT. GpuTest type [$gputest] 1130 | -------------------------------------------------------------------- DOWNLOAD 1131 | 1. Intel Power Gadget (2.3 MB) 5. Prime95 (1 MB) 1132 | 2. Graphics Layout Engine (13 MB) 6. HandBrakeCLI (6.9 MB) 1133 | 3. gfxCardStatus GPU switch (1 MB) 7. GpuTest (1.8 MB) 1134 | 4. Big Buck Bunny movie (691 MB) 1135 | ----------------------------------------------------------------------------- 1136 | Your choice: [Q=Quit] " 1137 | read ans 1138 | echo 1139 | [[ -z $ans || $ans = q || $ans = Q ]] && exit 0 1140 | 1141 | set -e 1142 | 1143 | strcmpi $ans 1 && { moh-get-ipg; continue; } 1144 | strcmpi $ans 2 && { moh-get-gle; continue; } 1145 | strcmpi $ans 5 && { moh-get-prime95; continue; } 1146 | strcmpi $ans 7 && { moh-get-gputest; continue; } 1147 | strcmpi $ans 6 && { moh-get-handbrake; continue; } 1148 | strcmpi $ans 4 && { moh-get-video; continue; } 1149 | strcmpi $ans 3 && { moh-get-gfx; continue; } 1150 | 1151 | strcmpi $ans g && { moh-do-gputest; [[ $menuquit = 1 ]] && exit || { anykey; continue; } } 1152 | strcmpi $ans p && { moh-do-prime95; [[ $menuquit = 1 ]] && exit || { anykey; continue; } } 1153 | strcmpi $ans y && { moh-do-x264-long; [[ $menuquit = 1 ]] && exit || { anykey; continue; } } 1154 | strcmpi $ans x && { moh-do-x264; [[ $menuquit = 1 ]] && exit || { anykey; continue; } } 1155 | strcmpi $ans f && { moh-do-fft; [[ $menuquit = 1 ]] && exit || { anykey; continue; } } 1156 | strcmpi $ans s && { moh-gpuswitch-menu; continue; } 1157 | 1158 | strcmpi $ans fd && { 1159 | read -p "FFT duration in seconds: [$fftduration] " x; 1160 | [[ $x -gt 0 ]] && editconf fftduration $x && continue 1161 | [[ -z $x ]] && continue 1162 | menuerr="FFT test duration must be a number greater than 0" 1163 | } 1164 | 1165 | strcmpi $ans ft && { 1166 | read -p "FFT number of threads (-1=cores-1, 0=maxthreads, n=any n > 0): [$fftthreads] " x; 1167 | [[ $x -ge -1 ]] && editconf fftthreads $x && continue 1168 | [[ -z $x ]] && continue 1169 | menuerr="FFT number of threads must be greater or equal to -1" 1170 | } 1171 | 1172 | strcmpi $ans fs && { 1173 | read -p "FFT size: [$fftsize] " x; 1174 | [[ $x -gt 1 ]] && editconf fftsize $x && continue 1175 | [[ -z $x ]] && continue 1176 | menuerr="FFT size must be a number greater than 1" 1177 | } 1178 | 1179 | strcmpi $ans pd && { 1180 | read -p "Prime95 duration in seconds: [$p95duration] " x; 1181 | [[ $x -gt 0 ]] && editconf p95duration $x && continue 1182 | [[ -z $x ]] && continue 1183 | menuerr="The Prime95 test duration must be a number greater than 0" 1184 | } 1185 | 1186 | strcmpi $ans ps && { 1187 | read -p "Prime95 fft min,max sizes in thousands, e.g. 8,16: [$p95min,$p95max] " x 1188 | [[ -z $x ]] && continue 1189 | x=(${x/[^0-9]/ }) 1190 | [[ ${x[0]} -le ${x[1]} && ${x[0]}${x[1]} =~ ^[0-9]+$ ]] && \ 1191 | editconf p95min ${x[0]} && editconf p95max ${x[1]} && continue 1192 | menuerr="The Prime95 fft min,max sizes must be a pair of positive integers with min <= max, e.g. 8,16" 1193 | } 1194 | 1195 | strcmpi $ans pm && { 1196 | read -p "Prime95 FFT memory (MB), use 0 to do the FFTs in-place (CPU stressful): [$p95mem] " x 1197 | [[ -z $x ]] && continue 1198 | free=$(freemb) 1199 | [[ -n $free ]] && let free2=free/2 1200 | [[ $x -ge 0 && $x =~ ^[0-9]+$ && ( -z $free || $x -le $free2 ) ]] && editconf p95mem $x && continue 1201 | menuerr="The Prime95 FFT memory must be a positive integer less than half your free RAM ($free/2=$free2)" 1202 | } 1203 | 1204 | strcmpi $ans gd && { 1205 | read -p "GpuTest duration in seconds: [$gpuduration] " x; 1206 | [[ $x -gt 0 ]] && editconf gpuduration $x && continue 1207 | [[ -z $x ]] && continue 1208 | menuerr="Duration must be a number greater than 0" 1209 | } 1210 | 1211 | strcmpi $ans gt && { 1212 | menu "Choose GpuTest benchmark:" "$gputest" ${gputesttypes//,/} 1213 | [[ $menuchoice = $gputest ]] || editconf gputest $menuchoice 1214 | continue 1215 | } 1216 | 1217 | strcmpi $ans gp && { 1218 | read -p "GpuTest priority in -19...20 (smaller values means higher priority): [$gpunice] " x; 1219 | [[ -z $x ]] && continue 1220 | [[ $x =~ ^-?[0-9]+$ && $x -ge -19 && $x -le 20 ]] && editconf gpunice $x && { 1221 | [[ $x -lt 0 ]] && anykey "Negative value entered, your password will be required. Press any key to continue ..." 1222 | continue 1223 | } 1224 | menuerr="Priority (niceness) must be an integer in -19...20" 1225 | } 1226 | 1227 | strcmpi $ans gr && { 1228 | read -p "GpuTest resolution: [${gpuwidth}x$gpuheight] " x 1229 | [[ -z $x ]] && continue 1230 | [[ $x =~ ^[0-9]+x[0-9]+$ ]] && editconf gpuwidth ${x/x*/} \ 1231 | && editconf gpuheight ${x/*x/} && continue 1232 | menuerr="Resolution must be MxN, where M and N are positive integers" 1233 | } 1234 | 1235 | strcmpi $ans gm && { 1236 | read -p "GpuTest MSAA value (0, 2, 4 or 8): [$gpumsaa] " x 1237 | [[ -z $x ]] && continue 1238 | [[ $x =~ ^[0248]$ ]] && editconf gpumsaa $x && continue 1239 | menuerr="MSAA value must be 0, 2, 4 or 8" 1240 | } 1241 | 1242 | strcmpi $ans hp && { 1243 | read -p "HandBrake priority in -19...20 (smaller values means higher priority): [$hbnice] " x; 1244 | [[ -z $x ]] && continue 1245 | [[ $x =~ ^-?[0-9]+$ && $x -ge -19 && $x -le 20 ]] && editconf hbnice $x && { 1246 | [[ $x -lt 0 ]] && anykey "Negative value entered, your password will be required. Press any key to continue ..." 1247 | continue 1248 | } 1249 | menuerr="Priority (niceness) must be an integer in -19...20" 1250 | } 1251 | 1252 | [[ -z $menuerr ]] && menuerr="Unknown option '$ans'" 1253 | anykey "Error: $menuerr. Press any key to continue ..." 1254 | done 1255 | -------------------------------------------------------------------------------- /make-release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rm -f macoh.zip 4 | zip macoh.zip CHANGELOG.md LICENSE README.md fftwtest macoh.conf macoh.sh 5 | -------------------------------------------------------------------------------- /mprime.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qnxor/macoh/5f9195a515f04198b40b2021ca25f2caca26c054/mprime.tgz --------------------------------------------------------------------------------