├── .github └── workflows │ └── test-n-publish.yml ├── .gitignore ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.rst ├── pylikwid.c ├── setup.py └── tests ├── monitoring.py ├── testaffinity.py ├── testfreq.py ├── testlib.py ├── testmarker.py ├── testpin.py └── testtopo.py /.github/workflows/test-n-publish.yml: -------------------------------------------------------------------------------- 1 | name: test-n-publish 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test-n-publish: 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | python-version: [3.5, 3.6, 3.7, 3.8] 11 | 12 | steps: 13 | - uses: actions/checkout@v2 14 | - uses: actions/setup-python@v2 15 | name: Set up Python ${{ matrix.python-version }} 16 | with: 17 | python-version: ${{ matrix.python-version }} 18 | - name: Pre-Install 19 | run: | 20 | git clone https://github.com/RRZE-HPC/likwid.git 21 | cd likwid 22 | make && sudo make install 23 | sudo modprobe msr 24 | - name: Install 25 | run: | 26 | python -m pip install --upgrade pip 27 | python setup.py build_ext 28 | python -m pip install -e . 29 | - name: Test 30 | run: | 31 | export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH 32 | python -c "import pylikwid" 33 | ./tests/testtopo.py 34 | ./tests/testpin.py 35 | ./tests/testaffinity.py 36 | - name: Build package 37 | run: | 38 | python setup.py build sdist 39 | - name: Publish to PyPI 40 | if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') 41 | uses: pypa/gh-action-pypi-publish@master 42 | with: 43 | skip_existing: true 44 | user: __token__ 45 | password: ${{ secrets.pypi_password }} 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | *.pyc 3 | *.so 4 | -------------------------------------------------------------------------------- /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. 340 | 341 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include README.rst 3 | include pylikwid.c 4 | include tests/*.py 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | INCLUDE_LIKWID=-I/usr/local/include 3 | LIBS_LIKWID=-L/usr/local/lib 4 | 5 | INCLUDE_PYTHON=-I/usr/include/python2.7 6 | LIBS_PYTHON= 7 | 8 | CFLAGS ?= -fPIC -shared 9 | 10 | TARGET=likwid.so 11 | 12 | INCLUDES= $(INCLUDE_LIKWID) $(INCLUDE_PYTHON) 13 | LIBPATHS= $(LIBS_LIKWID) $(LIBS_PYTHON) 14 | LIBS = -llikwid -lpython2.7 15 | 16 | 17 | $(TARGET): likwidmodule.c 18 | $(CC) $(CFLAGS) $(INCLUDES) $(LIBPATHS) $< -o $@ $(LIBS) 19 | 20 | clean: 21 | rm -rf $(TARGET) 22 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | pylikwid 2 | ======== 3 | 4 | Python interface for the C API of LIKWID 5 | (https://github.com/RRZE-HPC/likwid) 6 | 7 | .. image:: https://travis-ci.com/RRZE-HPC/pylikwid.svg?branch=master 8 | :target: https://travis-ci.com/RRZE-HPC/pylikwid?branch=master 9 | 10 | Installation 11 | ============ 12 | 13 | I added a setup.py script for the installation. It builds the C module 14 | and copies it to the proper destination. 15 | 16 | :: 17 | 18 | $ git clone https://github.com/RRZE-HPC/pylikwid.git 19 | $ cd pylikwid 20 | # Build C interface 21 | $ python setup.py build_ext -I -L -R 22 | # Install module to the proper location 23 | $ python setup.py install (--prefix=) 24 | # Testing 25 | $ python -c "import pylikwid" 26 | $ ./testlib.py 27 | 28 | Functions 29 | ========= 30 | 31 | After ``import pylikwid`` you can call the following functions: 32 | 33 | Marker API 34 | ---------- 35 | 36 | - ``pylikwid.markerinit()``: Initialize the Marker API of the LIKWID library. 37 | Must be called previous to all other functions. 38 | - ``pylikwid.markerthreadinit()``: Add the current thread to the Marker API. 39 | Since Python is commonly single-threaded simply call it directly 40 | after ``pylikwid.markerinit()`` 41 | - ``rr = pylikwid.registerregion(regiontag)``: Register a region to the 42 | Marker API. This is an optional function to reduce the overhead of 43 | region registration at ``pylikwid.markerstartregion``. If you don't call 44 | ``pylikwid.registerregion(regiontag)``, the registration is done at 45 | ``pylikwid.markerstartregion(regiontag)``. On success, 0 is return. If you 46 | havn't called ``pylikwid.markerinit()``, a negative number is returned. 47 | - ``err = pylikwid.markerstartregion(regiontag)``: Start measurements under 48 | the name ``regiontag``. On success, 0 is return. If you havn't called 49 | ``pylikwid.markerinit()``, a negative number is returned. 50 | - ``err = pylikwid.markerstopregion(regiontag)``: Stop measurements under the 51 | name ``regiontag`` again. On success, 0 is return. If you havn't 52 | called ``pylikwid.markerinit()``, a negative number is returned. 53 | - ``num_events, events[], time, count = pylikwid.markergetregion(regiontag)``: 54 | Get the intermediate results of the region identified by 55 | ``regiontag``. On success, it returns the number of events in the 56 | current group, a list with all the aggregated event results, the 57 | measurement time for the region and the number of calls. 58 | - ``pylikwid.nextgroup()``: Switch to the next event set in a 59 | round-robin fashion. If you have set only one event set on the 60 | command line, this function performs no operation. 61 | - ``pylikwid.markerreset(regiontag)``: Reset the values stored using the region 62 | name ``regiontag``. On success, 0 is returned. 63 | - ``pylikwid.markerclose()``: Close the connection to the LIKWID Marker API 64 | and write out measurement data to file. This file will be evaluated 65 | by ``likwid-perfctr``. 66 | - ``pylikwid.getprocessorid()``: Returns the ID of the currently 67 | executing CPU 68 | - ``pylikwid.pinprocess(cpuid)``: Pins the current process to the CPU 69 | given as ``cpuid``. 70 | - ``pylikwid.pinthread(cpuid)``: Pins the current thread to the CPU 71 | given as ``cpuid``. 72 | 73 | Topology 74 | -------- 75 | 76 | - ``pylikwid.inittopology()``: Initialize the topology module (reads in 77 | system topology) 78 | - ``infodict = pylikwid.getcpuinfo()``: Return a dict with general 79 | information about the system (CPU model, CPU family, ...) 80 | 81 | - ``osname``: Name of the CPU retrieved from the CPUID leafs 82 | - ``name``: Name of the micro architecture 83 | - ``short_name``: Short name of the micro architecture 84 | - ``family``: ID of the CPU family 85 | - ``model``: Vendor-specific model number of the CPU 86 | - ``stepping``: Stepping (Revision) of the CPU 87 | - ``perf_version``: Version number of the hardware performance 88 | monitoring capabilities 89 | - ``perf_num_ctr``: Amount of general-purpose counter registers per 90 | hardware thread 91 | - ``perf_num_fixed_ctr``: Amount of fixed-purpose counter registers 92 | per hardware thread 93 | - ``perf_width_ctr``: Bit length of the counter registers 94 | - ``clock``: CPU clock (only unequal to 0 if timer module is 95 | initialized) 96 | - ``turbo``: Is turbo mode supported? 97 | - ``isIntel``: Is it an Intel CPU? 98 | - ``supportUncore``: Does the system have performance monitoring 99 | counters in the Uncore? 100 | - ``features``: String with performance relevant CPU features (AVX, 101 | SSE, ...) 102 | - ``featureFlags``: Bitmask for all available CPU features 103 | 104 | - ``topodict = pylikwid.getcputopology()``: Return a dict with the 105 | topology of the system. Here is a list of fields in the dict: 106 | 107 | - ``numSockets``: Number of CPU sockets 108 | - ``numHWThreads``: Number of hardware threads (physical + 109 | hyperthreading cores) 110 | - ``activeHWThreads``: Number of active/usable hardware threads 111 | - ``numCoresPerSocket``: Amount of hardware threads per CPU socket 112 | - ``numThreadsPerCore``: Amount of hardware threads assembled in 113 | every physical CPU core 114 | - ``numCacheLevels``: Amount of levels in cacheing hierarchy 115 | - ``cacheLevels``: Dict with information about the cache levels, 116 | keys are the levels (1, 2, 3,...) 117 | 118 | - ``level``: Level of the cache in the hierarchy 119 | - ``lineSize``: Size of a cache line 120 | - ``sets``: Amount of sets 121 | - ``inclusive``: Is the cache inclusive or exclusive?\` 122 | - ``threads``: Amount of threads attached to the cache 123 | - ``associativity``: Associativity of the cache 124 | - ``type``: data (= data cache), unified = (data + instruction 125 | cache) 126 | - ``size``: Size of the cache in bytes 127 | 128 | - ``threadPool``: Dict with information about the hardware threads. 129 | Keys are the os-generated ID of the hardware thread 130 | 131 | - ``coreId``: ID of the corresponding physical core 132 | - ``apicId``: ID set by the operating system 133 | - ``threadId``: ID of the hardware thread in the physical core 134 | - ``packageId``: ID of the CPU socket hosting the hardware thread 135 | 136 | - ``pylikwid.printsupportedcpus()``: Prints all supported micro 137 | architecture names to stdout 138 | - ``pylikwid.finalizetopology()``: Delete all information in the 139 | topology module 140 | 141 | NUMA 142 | ---- 143 | 144 | - ``numadict = pylikwid.initnuma()``: Initialize the NUMA module and 145 | return the gathered values 146 | 147 | - ``numberOfNodes``: Amount of NUMA nodes in the system 148 | - ``nodes``: Dict holding the information about the NUMA domains. 149 | Keys are the NUMA domain IDs 150 | 151 | - ``id``: ID of the NUMA domain (should be equal to dict key) 152 | - ``numberOfProcessors``: Number of hardware threads attached to 153 | the NUMA domain 154 | - ``processors``: List of all CPU IDs attached to the NUMA domain 155 | - ``freeMemory``: Amount of free memory in the NUMA domain (in 156 | Kbytes) 157 | - ``totalMemory``: Amount of total memory in the NUMA domain (in 158 | Kbytes) 159 | - ``numberOfDistances``: How many distances to self/other NUMA 160 | domains 161 | - ``distances``: List with distances, NUMA domain IDs are the 162 | destination indexes in the list 163 | 164 | - ``pylikwid.finalizenuma()``: Delete all information in the NUMA 165 | module 166 | 167 | Affinity 168 | -------- 169 | 170 | - ``affdict = pylikwid.initaffinity()``: Initialize the affinity domain 171 | module and return the gathered values 172 | 173 | - ``numberOfAffinityDomains``: Amount of affinity domains 174 | - ``numberOfSocketDomains``: Amount of CPU socket related affinity 175 | domains 176 | - ``numberOfNumaDomains``: Amount of NUMA related affinity domains 177 | - ``numberOfCacheDomains``: Amount of last level cache related 178 | affinity domains 179 | - ``numberOfProcessorsPerSocket``: Amount of hardware threads per 180 | CPU socket 181 | - ``numberOfCoresPerCache``: Amount of physical CPU cores per last 182 | level cache 183 | - ``numberOfProcessorsPerCache``: Amount of hardware threads per 184 | last level cache 185 | - ``domains``: Dict holding the information about the affinity 186 | domains 187 | 188 | - ``tag``: Name of the affinity domain (N = node, SX = socket X, 189 | CY = cache Y, MZ = memory domain Z) 190 | - ``numberOfProcessors``: Amount of hardware threads in the 191 | domain 192 | - ``numberOfCores``: Amount of physical CPU cores in the domain 193 | - ``processorList``: List holding the CPU IDs in the domain 194 | 195 | - ``pylikwid.finalizeaffinity()``: Delete all information in the 196 | affinity domain module 197 | - ``pylikwid.cpustr_to_cpulist()``: Transform a valid cpu string in 198 | LIKWID syntax into a list of CPU IDs 199 | 200 | Timer 201 | ----- 202 | 203 | - ``pylikwid.getcpuclock()``: Return the CPU clock 204 | - ``t_start = pylikwid.startclock()``: Start the clock and return the 205 | current timestamp 206 | - ``t_end = pylikwid.stopclock()``: Stop the clock and return the 207 | current timestamp 208 | - ``t = pylikwid.getclock(t_start, t_end)``: Return the time in seconds 209 | between ``t_start`` and ``t_end`` 210 | - ``c = pylikwid.getclockcycles(t_start, t_end)``: Return the amount of 211 | CPU cycles between ``t_start`` and ``t_end`` 212 | 213 | Temperature 214 | ----------- 215 | 216 | - ``pylikwid.inittemp(cpu)``: Initialize the temperature module for CPU 217 | ``cpu`` 218 | - ``pylikwid.readtemp(cpu)``: Read the current temperature of CPU 219 | ``cpu`` 220 | 221 | Energy 222 | ------ 223 | 224 | - ``pinfo = pylikwid.getpowerinfo()``: Initializes the energy module 225 | and returns gathered information. If it returns ``None``, there is no 226 | energy support 227 | 228 | - ``minFrequency``: Minimal possible frequency of a CPU core 229 | - ``baseFrequency``: Base frequency of a CPU core 230 | - ``hasRAPL``: Are energy reading supported? 231 | - ``timeUnit``: Time unit 232 | - ``powerUnit``: Power unit 233 | - ``domains``: Dict holding the information about the energy 234 | domains. Keys are PKG, PP0, PP1, DRAM 235 | 236 | - ``ID``: ID of the energy domain 237 | - ``energyUnit``: Unit to derive raw register counts to uJ 238 | - ``supportInfo``: Is the information register available? 239 | - ``tdp``: TDP of the domain (only if supportInfo == True) 240 | - ``minPower``: Minimal power consumption by the domain (only if 241 | supportInfo == True) 242 | - ``maxPower``: Maximal power consumption by the domain (only if 243 | supportInfo == True) 244 | - ``maxTimeWindow``: Maximal time window between updates of the 245 | energy registers 246 | - ``supportStatus``: Are energy readings from the domain are 247 | possible? 248 | - ``supportPerf``: Is power capping etc. available? 249 | - ``supportPolicy``: Can we set a power policy for the domain? 250 | 251 | - ``e_start = pylikwid.startpower(cpu, domainid)``: Return the start 252 | value for a cpu for the domain with ``domainid``. The ``domainid`` 253 | can be found in ``pinfo["domains"][domainname]["ID"]`` 254 | - ``e_stop = pylikwid.stoppower(cpu, domainid)``: Return the stop value 255 | for a cpu for the domain with ``domainid``. The ``domainid`` can be 256 | found in ``pinfo["domains"][domainname]["ID"]`` 257 | - ``e = pylikwid.getpower(e_start, e_stop, domainid)``: Calculate the 258 | uJ from the values retrieved by ``startpower`` and ``stoppower``. 259 | 260 | Configuration 261 | ------------- 262 | 263 | - ``pylikwid.initconfiguration()``: Read in config file from different 264 | places. Default is ``/etc/likwid.cfg`` 265 | - ``config = pylikwid.getconfiguration()``: Get the dict with the 266 | configuration options 267 | 268 | - ``configFileName``: Path to the config file 269 | - ``topologyCfgFileName``: If a topology file was created with 270 | ``likwid-genTopoCfg`` and found by ``initconfiguration()`` 271 | - ``daemonPath``: Path to the access daemon executable 272 | - ``groupPath``: Path to the base directory with the performance 273 | group files 274 | - ``daemonMode``: Configured access mode (0=direct, 1=accessDaemon) 275 | - ``maxNumThreads``: Maximal amount of hardware threads that can be 276 | handled by LIKWID 277 | - ``maxNumNodes``: Maximal amount of CPU sockets that can be handled 278 | by LIKWID 279 | 280 | - ``pylikwid.destroyconfiguration()``: Destroy all information about 281 | the configuration 282 | 283 | Access module 284 | ------------- 285 | 286 | - ``pylikwid.hpmmode(mode)``: Set access mode. For x86 there are two 287 | modes: 288 | 289 | - ``mode = 0``: Access the MSR and PCI devices directly. May require 290 | root access 291 | - ``mode = 1``: Access the MSR and PCI devices through access daemon 292 | instances 293 | 294 | - ``pylikwid.hpminit()``: Initialize the access functions according to 295 | the access mode 296 | - ``pylikwid.hpmaddthread(cpu)``: Add CPU ``cpu`` to the access layer 297 | (opens devices files or connection to an access daemon) 298 | - ``pylikwid.hpmfinalize()``: Unregister all CPUs from the access layer 299 | and close files/connections 300 | 301 | Performance Monitoring 302 | ---------------------- 303 | 304 | - ``pylikwid.init(cpus)``: Initialize the perfmon module for the CPUs 305 | given in list ``cpus`` 306 | - ``pylikwid.getnumberofthreads()``: Return the number of threads 307 | initialized in the perfmon module 308 | - ``pylikwid.getnumberofgroups()``: Return the number of groups 309 | currently registered in the perfmon module 310 | - ``pylikwid.getgroups()``: Return a list of all available groups. Each 311 | list entry is a dict: 312 | 313 | - ``Name``: Name of the performance group 314 | - ``Short``: Short information about the performance group 315 | - ``Long``: Long description of the performance group 316 | 317 | - ``gid = pylikwid.addeventset(estr)``: Add a performance group or a 318 | custom event set to the perfmon module. The ``gid`` is required to 319 | specify the event set later 320 | - ``pylikwid.getnameofgroup(gid)``: Return the name of the group 321 | identified by ``gid``. If it is a custom event set, the name is set 322 | to ``Custom`` 323 | - ``pylikwid.getshortinfoofgroup(gid)``: Return the short information 324 | about a performance group 325 | - ``pylikwid.getlonginfoofgroup(gid)``: Return the description of a 326 | performance group 327 | - ``pylikwid.getnumberofevents(gid)``: Return the amount of events in 328 | the group 329 | - ``pylikwid.getnumberofmetrics(gid)``: Return the amount of derived 330 | metrics in the group. Always 0 for custom event sets. 331 | - ``pylikwid.getnameofevent(gid, eidx)``: Return the name of the event 332 | identified by ``gid`` and the index in the list of events 333 | - ``pylikwid.getnameofcounter(gid, eidx)``: Return the name of the 334 | counter register identified by ``gid`` and the index in the list of 335 | events 336 | - ``pylikwid.getnameofmetric(gid, midx)``: Return the name of a derived 337 | metric identified by ``gid`` and the index in the list of metrics 338 | - ``pylikwid.setup(gid)``: Program the counter registers to measure all 339 | events in group ``gid`` 340 | - ``pylikwid.start()``: Start the counter registers 341 | - ``pylikwid.stop()``: Stop the counter registers 342 | - ``pylikwid.read()``: Read the counter registers (stop->read->start) 343 | - ``pylikwid.switch(gid)``: Switch to group ``gid`` 344 | (stop->setup(gid)->start) 345 | - ``pylikwid.getidofactivegroup()`` Return the ``gid`` of the currently 346 | configured group 347 | - ``pylikwid.getresult(gid, eidx, tidx)``: Return the raw counter 348 | register result of all measurements identified by group ``gid`` and 349 | the indices for event ``eidx`` and thread ``tidx`` 350 | - ``pylikwid.getlastresult(gid, eidx, tidx)``: Return the raw counter 351 | register result of the last measurement cycle identified by group 352 | ``gid`` and the indices for event ``eidx`` and thread ``tidx`` 353 | - ``pylikwid.getmetric(gid, midx, tidx)``: Return the derived metric 354 | result of all measurements identified by group ``gid`` and the 355 | indices for metric ``midx`` and thread ``tidx`` 356 | - ``pylikwid.getlastmetric(gid, midx, tidx)``: Return the derived 357 | metric result of the last measurement cycle identified by group 358 | ``gid`` and the indices for metric ``midx`` and thread ``tidx`` 359 | - ``pylikwid.gettimeofgroup(gid)``: Return the measurement time for 360 | group identified by ``gid`` 361 | - ``pylikwid.finalize()``: Reset all used registers and delete internal 362 | measurement results 363 | 364 | Marker API result file reader 365 | ----------------------------- 366 | 367 | - ``pylikwid.markerreadfile(filename)``: Reads in the result file of an 368 | application run instrumented by the LIKWID Marker API 369 | - ``pylikwid.markernumregions()``: Return the number of regions in an 370 | application run 371 | - ``pylikwid.markerregiontag(rid)``: Return the region tag for the 372 | region identified by ``rid`` 373 | - ``pylikwid.markerregiongroup(rid)``: Return the group name for the 374 | region identified by ``rid`` 375 | - ``pylikwid.markerregionevents(rid)``: Return the amount of events for 376 | the region identified by ``rid`` 377 | - ``pylikwid.markerregionthreads(rid)``: Return the amount of threads 378 | that executed the region identified by ``rid`` 379 | - ``pylikwid.markerregiontime(rid, tidx)``: Return the accumulated 380 | measurement time for the region identified by ``rid`` and the thread 381 | index ``tidx`` 382 | - ``pylikwid.markerregioncount(rid, tidx)``: Return the call count for 383 | the region identified by ``rid`` and the thread index ``tidx`` 384 | - ``pylikwid.markerregionresult(rid, eidx, tidx)``: Return the call 385 | count for the region identified by ``rid``, the event index ``eidx`` 386 | and the thread index ``tidx`` 387 | - ``pylikwid.markerregionmetric(rid, midx, tidx)``: Return the call 388 | count for the region identified by ``rid``, the metric index ``midx`` 389 | and the thread index ``tidx`` 390 | 391 | GPU Topology (if LIKWID is built with Nvidia interface) 392 | ------------------------------------------------------- 393 | 394 | - ``pylikwid.initgputopology()``: Initialize the topology module (reads in 395 | system topology) 396 | 397 | - ``topolist = pylikwid.getgputopology()``: Return a list with the 398 | GPU topology of the system. Each GPU is represented by a dict. The entries in 399 | the dicts are: 400 | 401 | - ``devid``: Device identifier for the GPU 402 | - ``numaNode``: The NUMA node identifier the GPU is attached at 403 | - ``name``: Name of the device 404 | - ``mem``: Memory capacity of the device 405 | - ``ccapMajor``: Major number of the compute capability 406 | - ``ccapMinor``: Minor number of the compute capability 407 | - ``maxThreadsDim[3]``: Maximum sizes of each dimension of a block 408 | - ``maxGridSize[3]``: Maximum sizes of each dimension of a grid 409 | - ``maxThreadsPerBlock``: Maximam number of thread per block 410 | - ``sharedMemPerBlock``: Total amount of shared memory available per block 411 | - ``totalConstantMemory``: Total amount of constant memory available on the device 412 | - ``simdWidth``: SIMD width of arithmetic units = warp size 413 | - ``memPitch``: Maximum pitch allowed by the memory copy functions that involve memory regions allocated through cuMemAllocPitch() 414 | - ``regsPerBlock``: Total number of registers available per block 415 | - ``clockRatekHz``: Clock frequency in kilohertz 416 | - ``textureAlign``: Alignment requirement 417 | - ``surfaceAlign``: Alignment requirement for surfaces 418 | - ``l2Size``: L2 cache in bytes. 0 if the device doesn't have L2 cache 419 | - ``memClockRatekHz``: Peak memory clock frequency in kilohertz 420 | - ``pciBus``: PCI bus identifier of the device 421 | - ``pciDev``: PCI device (also known as slot) identifier of the device 422 | - ``pciDom``: PCI domain identifier of the device 423 | - ``maxBlockRegs``: Maximum number of 32-bit registers available to a thread block 424 | - ``numMultiProcs``: Number of multiprocessors on the device 425 | - ``maxThreadPerMultiProc``: Maximum resident threads per multiprocessor 426 | - ``memBusWidth``: Global memory bus width in bits 427 | - ``unifiedAddrSpace``: 1 if the device shares a unified address space with the host, or 0 if not 428 | - ``ecc``: 1 if error correction is enabled on the device, 0 if error correction is disabled or not supported by the device 429 | - ``asyncEngines``: Number of asynchronous engines 430 | - ``mapHostMem``: 1 if the device can map host memory into the CUDA address space 431 | - ``integrated``: 1 if the device is an integrated (motherboard) GPU and 0 if it is a discrete (card) component 432 | 433 | - ``pylikwid.finalizegputopology()``: Delete all information in the 434 | topology module 435 | 436 | 437 | Performance Monitoring for Nvidia GPUs (if LIKWID is built with Nvidia interface) 438 | --------------------------------------------------------------------------------- 439 | 440 | - ``pylikwid.nvinit(gpus)``: Initialize the nvmon module for the GPUs 441 | given in list ``gpus`` 442 | - ``pylikwid.nvgetnumberofgpus()``: Return the number of GPUs 443 | initialized in the nvmon module 444 | - ``pylikwid.nvgetnumberofgroups()``: Return the number of groups 445 | currently registered in the nvmon module 446 | - ``pylikwid.nvgetgroups()``: Return a list of all available groups. Each 447 | list entry is a dict: 448 | 449 | - ``Name``: Name of the performance group 450 | - ``Short``: Short information about the performance group 451 | - ``Long``: Long description of the performance group 452 | 453 | - ``gid = pylikwid.nvaddeventset(estr)``: Add a performance group or a 454 | custom event set to the perfmon module. The ``gid`` is required to 455 | specify the event set later 456 | - ``pylikwid.nvgetnameofgroup(gid)``: Return the name of the group 457 | identified by ``gid``. If it is a custom event set, the name is set 458 | to ``Custom`` 459 | - ``pylikwid.nvgetshortinfoofgroup(gid)``: Return the short information 460 | about a performance group 461 | - ``pylikwid.nvgetlonginfoofgroup(gid)``: Return the description of a 462 | performance group 463 | - ``pylikwid.nvgetnumberofevents(gid)``: Return the amount of events in 464 | the group 465 | - ``pylikwid.nvgetnumberofmetrics(gid)``: Return the amount of derived 466 | metrics in the group. Always 0 for custom event sets. 467 | - ``pylikwid.nvgetnameofevent(gid, eidx)``: Return the name of the event 468 | identified by ``gid`` and the index in the list of events 469 | - ``pylikwid.nvgetnameofcounter(gid, eidx)``: Return the name of the 470 | counter register identified by ``gid`` and the index in the list of 471 | events 472 | - ``pylikwid.nvgetnameofmetric(gid, midx)``: Return the name of a derived 473 | metric identified by ``gid`` and the index in the list of metrics 474 | - ``pylikwid.nvsetup(gid)``: Program the counter registers to measure all 475 | events in group ``gid`` 476 | - ``pylikwid.nvstart()``: Start the counter registers 477 | - ``pylikwid.nvstop()``: Stop the counter registers 478 | - ``pylikwid.nvread()``: Read the counter registers (stop->read->start) 479 | - ``pylikwid.nvswitch(gid)``: Switch to group ``gid`` 480 | (stop->setup(gid)->start) 481 | - ``pylikwid.nvgetidofactivegroup()`` Return the ``gid`` of the currently 482 | configured group 483 | - ``pylikwid.nvgetresult(gid, eidx, tidx)``: Return the raw counter 484 | register result of all measurements identified by group ``gid`` and 485 | the indices for event ``eidx`` and thread ``tidx`` 486 | - ``pylikwid.nvgetlastresult(gid, eidx, tidx)``: Return the raw counter 487 | register result of the last measurement cycle identified by group 488 | ``gid`` and the indices for event ``eidx`` and thread ``tidx`` 489 | - ``pylikwid.nvgetmetric(gid, midx, tidx)``: Return the derived metric 490 | result of all measurements identified by group ``gid`` and the 491 | indices for metric ``midx`` and thread ``tidx`` 492 | - ``pylikwid.nvgetlastmetric(gid, midx, tidx)``: Return the derived 493 | metric result of the last measurement cycle identified by group 494 | ``gid`` and the indices for metric ``midx`` and thread ``tidx`` 495 | - ``pylikwid.nvgettimeofgroup(gid)``: Return the measurement time for 496 | group identified by ``gid`` 497 | - ``pylikwid.nvfinalize()``: Reset all used registers and delete internal 498 | measurement results 499 | 500 | Nvmon Marker API (if LIKWID is built with Nvidia interface) 501 | ----------------------------------------------------------- 502 | 503 | - ``pylikwid.gpumarkerinit()``: Initialize the Nvmon Marker API of the LIKWID library. 504 | Must be called previous to all other functions. 505 | - ``rr = pylikwid.gpuregisterregion(regiontag)``: Register a region to the 506 | Nvmon Marker API. This is an optional function to reduce the overhead of 507 | region registration at ``pylikwid.markerstartregion``. If you don't call 508 | ``pylikwid.gpumarkerregisterregion(regiontag)``, the registration is done at 509 | ``pylikwid.gpumarkerstartregion(regiontag)``. On success, 0 is return. If you 510 | havn't called ``pylikwid.gpumarkerinit()``, a negative number is returned. 511 | - ``err = pylikwid.gpumarkerstartregion(regiontag)``: Start measurements under 512 | the name ``regiontag``. On success, 0 is return. If you havn't called 513 | ``pylikwid.gpumarkerinit()``, a negative number is returned. 514 | - ``err = pylikwid.gpumarkerstopregion(regiontag)``: Stop measurements under the 515 | name ``regiontag`` again. On success, 0 is return. If you havn't 516 | called ``pylikwid.gpumarkerinit()``, a negative number is returned. 517 | - ``num_gpus, num_events, events[][], time[], count[] = pylikwid.gpumarkergetregion(regiontag)``: 518 | Get the intermediate results of the region identified by 519 | ``regiontag``. On success, it returns the number of events in the 520 | current group, a list with all the aggregated event results per GPU, the 521 | measurement time for the region and the number of calls. 522 | - ``pylikwid.gpunextgroup()``: Switch to the next event set in a 523 | round-robin fashion. If you have set only one event set on the 524 | command line, this function performs no operation. 525 | - ``pylikwid.gpumarkerreset(regiontag)``: Reset the values stored using the region 526 | name ``regiontag``. On success, 0 is returned. 527 | - ``pylikwid.gpumarkerclose()``: Close the connection to the LIKWID Nvmon Marker API 528 | and write out measurement data to file. This file will be evaluated 529 | by ``likwid-perfctr``. 530 | 531 | 532 | Usage 533 | ===== 534 | 535 | Marker API 536 | ---------- 537 | 538 | Code 539 | ~~~~ 540 | 541 | Here is a small example Python script how to use the LIKWID Marker API 542 | in Python: 543 | 544 | :: 545 | 546 | #!/usr/bin/env python 547 | 548 | import pylikwid 549 | 550 | pylikwid.markerinit() 551 | pylikwid.markerthreadinit() 552 | liste = [] 553 | pylikwid.markerstartregion("listappend") 554 | for i in range(0,1000000): 555 | liste.append(i) 556 | pylikwid.markerstopregion("listappend") 557 | nr_events, eventlist, time, count = pylikwid.markergetregion("listappend") 558 | for i, e in enumerate(eventlist): 559 | print(i, e) 560 | pylikwid.markerclose() 561 | 562 | This code simply measures the hardware performance counters for 563 | appending 1000000 elements to a list. First the API is initialized with 564 | ``likwid.init()`` and ``likwid.threadinit()``. Afterwards it creates an 565 | empty list, starts the measurements with 566 | ``likwid.startregion("listappend")`` and executes the appending loop. 567 | When the loop has finished, we stop the measurements again using 568 | ``likwid.stopregion("listappend")``. Just for the example, we get the 569 | values inside our script using ``likwid.getregion("listappend")`` and 570 | print out the results. Finally, we close the connection to the LIKWID 571 | Marker API. 572 | 573 | You always have to use ``likwid-perfctr`` to program the hardware 574 | performance counters and specify the CPUs that should be measured. Since 575 | Python is commonly single-threaded, the cpu set only contains one entry: 576 | ``likwid-perfctr -C 0 -g -m `` This pins the 577 | Python interpreter to CPU 0 and measures ```` for all regions 578 | in the Python script. You can set multiple event sets by adding multiple 579 | ``-g `` to the command line. Please see the LIKWID page for 580 | further information how to use ``likwid-perfctr``. Link: 581 | https://github.com/rrze-likwid/likwid 582 | 583 | Example 584 | ~~~~~~~ 585 | 586 | Using the above Python script we can measure the L2 to L3 cache data 587 | volume: 588 | 589 | :: 590 | 591 | $ likwid-perfctr -C 0 -g L3 -m ./test.py 592 | -------------------------------------------------------------------------------- 593 | CPU name: Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz 594 | CPU type: Intel Core Haswell processor 595 | CPU clock: 3.39 GHz 596 | -------------------------------------------------------------------------------- 597 | (0, 926208305.0) 598 | (1, 325539316.0) 599 | (2, 284626172.0) 600 | (3, 1219118.0) 601 | (4, 918368.0) 602 | Wrote LIKWID Marker API output to file /tmp/likwid_17275.txt 603 | -------------------------------------------------------------------------------- 604 | ================================================================================ 605 | Group 1 L3: Region listappend 606 | ================================================================================ 607 | +-------------------+----------+ 608 | | Region Info | Core 0 | 609 | +-------------------+----------+ 610 | | RDTSC Runtime [s] | 0.091028 | 611 | | call count | 1 | 612 | +-------------------+----------+ 613 | 614 | +-----------------------+---------+--------------+ 615 | | Event | Counter | Core 0 | 616 | +-----------------------+---------+--------------+ 617 | | INSTR_RETIRED_ANY | FIXC0 | 9.262083e+08 | 618 | | CPU_CLK_UNHALTED_CORE | FIXC1 | 3.255393e+08 | 619 | | CPU_CLK_UNHALTED_REF | FIXC2 | 2.846262e+08 | 620 | | L2_LINES_IN_ALL | PMC0 | 1.219118e+06 | 621 | | L2_TRANS_L2_WB | PMC1 | 9.183680e+05 | 622 | +-----------------------+---------+--------------+ 623 | 624 | +-------------------------------+--------------+ 625 | | Metric | Core 0 | 626 | +-------------------------------+--------------+ 627 | | Runtime (RDTSC) [s] | 0.09102752 | 628 | | Runtime unhalted [s] | 9.596737e-02 | 629 | | Clock [MHz] | 3.879792e+03 | 630 | | CPI | 3.514753e-01 | 631 | | L3 load bandwidth [MBytes/s] | 8.571425e+02 | 632 | | L3 load data volume [GBytes] | 0.078023552 | 633 | | L3 evict bandwidth [MBytes/s] | 6.456899e+02 | 634 | | L3 evict data volume [GBytes] | 0.058775552 | 635 | | L3 bandwidth [MBytes/s] | 1.502832e+03 | 636 | | L3 data volume [GBytes] | 0.136799104 | 637 | +-------------------------------+--------------+ 638 | 639 | At first a header with the current system type and clock is printed. 640 | Afterwards the output of the Python script lists the results of the 641 | measurements we got internally with ``likwid.getregion``. The next 642 | output is the region results evaluated by ``likwid-perfctr`` and prints 643 | at first a headline stating the measured eventset, here ``L3`` and the 644 | region name ``listappend``. Afterwards 2 or 3 tables are printed. At 645 | first some basic information about the region like run time (or better 646 | measurement time) and the number of calls of the region. The next table 647 | contains the raw values for each event in the eventset. These numbers 648 | are similar to the ones we got internally with ``likwid.getregion``. If 649 | you have set an performance group (here ``L3``) instead of a custom 650 | event set, the raw results are derived to commonly used metrics, here 651 | the ``CPI`` (Cycles per instruction, lower is better) and different 652 | bandwidths and data volumes. You can see, that the load bandwidth for 653 | the small loop is 857 MByte/s and the evict (write) bandwidth is 645 654 | MByte/s. In total we have a bandwidth of 1502 MByte/s. 655 | 656 | Full API 657 | -------- 658 | 659 | Code 660 | ~~~~ 661 | 662 | :: 663 | 664 | #!/usr/bin/env python 665 | 666 | import pylikwid 667 | 668 | liste = [] 669 | cpus = [0,1] 670 | 671 | pylikwid.init(cpus) 672 | group = pylikwid.addeventset("INSTR_RETIRED_ANY:FIXC0") 673 | pylikwid.setup(group) 674 | pylikwid.start() 675 | for i in range(0,1000000): 676 | liste.append(i) 677 | pylikwid.stop() 678 | for thread in range(0,len(cpus)): 679 | print("Result CPU %d : %f" % (cpus[thread], pylikwid.getresult(group,0,thread))) 680 | pylikwid.finalize() 681 | 682 | Example 683 | ~~~~~~~ 684 | 685 | :: 686 | 687 | $ ./test.py 688 | Result CPU 0 : 87335.000000 689 | Result CPU 1 : 5222188.000000 690 | 691 | Further comments 692 | ================ 693 | 694 | Please be aware that Python is a high-level language and your simple 695 | code is translated to a lot of Assembly instructions. The ``CPI`` value 696 | is commonly low (=> good) for high-level languages because they have to 697 | perform type-checking and similar stuff that can be executed fast in 698 | comparison to the CPU clock. If you would compare the results to a lower 699 | level language like C or Fortran, the ``CPI`` will be worse for them but 700 | the performance will be higher as no type-checking and transformations 701 | need to be done. 702 | -------------------------------------------------------------------------------- /pylikwid.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include 5 | 6 | #define PYSTR(str) (Py_BuildValue("s", str)) 7 | #define PYINT(val) (Py_BuildValue("i", val)) 8 | #define PYUINT(val) (Py_BuildValue("I", val)) 9 | 10 | #ifndef NAN 11 | #define NAN (0.0/0.0) 12 | #endif 13 | 14 | static int access_initialized = 0; 15 | static int topo_initialized = 0; 16 | CpuInfo_t cpuinfo = NULL; 17 | CpuTopology_t cputopo = NULL; 18 | static int config_initialized = 0; 19 | Configuration_t configfile = NULL; 20 | static int numa_initialized = 0; 21 | NumaTopology_t numainfo = NULL; 22 | static int affinity_initialized = 0; 23 | AffinityDomains_t affinity = NULL; 24 | static int power_initialized = 0; 25 | PowerInfo_t power; 26 | static int timer_initialized = 0; 27 | static int perfmon_initialized = 0; 28 | 29 | static PyObject * 30 | likwid_lversion(PyObject *self, PyObject *args) 31 | { 32 | int v = 0, r = 0, m = 0; 33 | #ifdef LIKWID_MAJOR 34 | v = LIKWID_MAJOR; 35 | r = LIKWID_RELEASE; 36 | m = LIKWID_MINOR; 37 | #else 38 | v = 4; 39 | r = 3; 40 | m = 4; 41 | #endif 42 | return Py_BuildValue("iii", v, r, m); 43 | } 44 | 45 | /* 46 | ################################################################################ 47 | # Marker API related functions 48 | ################################################################################ 49 | */ 50 | 51 | static PyObject * 52 | likwid_markerinit(PyObject *self, PyObject *args) 53 | { 54 | likwid_markerInit(); 55 | Py_RETURN_NONE; 56 | } 57 | 58 | static PyObject * 59 | likwid_markerthreadinit(PyObject *self, PyObject *args) 60 | { 61 | likwid_markerThreadInit(); 62 | Py_RETURN_NONE; 63 | } 64 | 65 | static PyObject * 66 | likwid_markerregisterregion(PyObject *self, PyObject *args) 67 | { 68 | const char *regiontag; 69 | int ret; 70 | if (!PyArg_ParseTuple(args, "s", ®iontag)) 71 | return NULL; 72 | 73 | ret = likwid_markerRegisterRegion(regiontag); 74 | return Py_BuildValue("i", ret); 75 | } 76 | 77 | static PyObject * 78 | likwid_markerstartregion(PyObject *self, PyObject *args) 79 | { 80 | const char *regiontag; 81 | int ret; 82 | if (!PyArg_ParseTuple(args, "s", ®iontag)) 83 | return NULL; 84 | 85 | ret = likwid_markerStartRegion(regiontag); 86 | return Py_BuildValue("i", ret); 87 | } 88 | 89 | static PyObject * 90 | likwid_markerstopregion(PyObject *self, PyObject *args) 91 | { 92 | const char *regiontag; 93 | int ret; 94 | if (!PyArg_ParseTuple(args, "s", ®iontag)) 95 | return NULL; 96 | 97 | ret = likwid_markerStopRegion(regiontag); 98 | return Py_BuildValue("i", ret); 99 | } 100 | 101 | static PyObject * 102 | likwid_markergetregion(PyObject *self, PyObject *args) 103 | { 104 | int i; 105 | int currentGroup = 0; 106 | const char *regiontag = NULL; 107 | int nr_events = 0; 108 | double* events = NULL; 109 | double time = 0; 110 | int count = 0; 111 | Py_ssize_t pyLen = 0; 112 | PyObject *pyList; 113 | if (!PyArg_ParseTuple(args, "s", ®iontag)) 114 | return NULL; 115 | currentGroup = perfmon_getIdOfActiveGroup(); 116 | nr_events = perfmon_getNumberOfEvents(currentGroup); 117 | events = (double*) malloc(nr_events * sizeof(double)); 118 | if (events == NULL) 119 | { 120 | return NULL; 121 | } 122 | for (i = 0; i < nr_events; i++) 123 | { 124 | events[i] = 0.0; 125 | } 126 | pyLen = (Py_ssize_t)nr_events; 127 | pyList = PyList_New(pyLen); 128 | likwid_markerGetRegion(regiontag, &nr_events, events, &time, &count); 129 | for (i=0; i< nr_events; i++) 130 | { 131 | PyList_SET_ITEM(pyList, (Py_ssize_t)i, Py_BuildValue("d", events[i])); 132 | } 133 | free(events); 134 | return Py_BuildValue("iOdi", nr_events, pyList, time, count); 135 | } 136 | 137 | static PyObject * 138 | likwid_markernextgroup(PyObject *self, PyObject *args) 139 | { 140 | likwid_markerNextGroup(); 141 | Py_RETURN_NONE; 142 | } 143 | 144 | static PyObject * 145 | likwid_markerresetregion(PyObject *self, PyObject *args) 146 | { 147 | const char *regiontag; 148 | int ret; 149 | if (!PyArg_ParseTuple(args, "s", ®iontag)) 150 | return NULL; 151 | 152 | ret = likwid_markerResetRegion(regiontag); 153 | return Py_BuildValue("i", ret); 154 | } 155 | 156 | 157 | static PyObject * 158 | likwid_markerclose(PyObject *self, PyObject *args) 159 | { 160 | likwid_markerClose(); 161 | Py_RETURN_NONE; 162 | } 163 | 164 | 165 | static PyObject * 166 | likwid_getprocessorid(PyObject *self, PyObject *args) 167 | { 168 | return Py_BuildValue("i", likwid_getProcessorId()); 169 | } 170 | 171 | static PyObject * 172 | likwid_pinprocess(PyObject *self, PyObject *args) 173 | { 174 | int cpuid, ret; 175 | if (!PyArg_ParseTuple(args, "i", &cpuid)) 176 | return NULL; 177 | ret = likwid_pinProcess(cpuid); 178 | return Py_BuildValue("i", ret); 179 | } 180 | 181 | static PyObject * 182 | likwid_pinthread(PyObject *self, PyObject *args) 183 | { 184 | int cpuid, ret; 185 | if (!PyArg_ParseTuple(args, "i", &cpuid)) 186 | return NULL; 187 | ret = likwid_pinThread(cpuid); 188 | return Py_BuildValue("i", ret); 189 | } 190 | 191 | /* 192 | ################################################################################ 193 | # Misc functions 194 | ################################################################################ 195 | */ 196 | 197 | static PyObject * 198 | likwid_setverbosity(PyObject *self, PyObject *args) 199 | { 200 | int verbosity; 201 | if (!PyArg_ParseTuple(args, "i", &verbosity)) 202 | return NULL; 203 | if (verbosity >= DEBUGLEV_ONLY_ERROR && verbosity <= DEBUGLEV_DEVELOP) 204 | { 205 | perfmon_setVerbosity(verbosity); 206 | return Py_BuildValue("i", verbosity); 207 | } 208 | return Py_BuildValue("i", -1); 209 | } 210 | 211 | /* 212 | ################################################################################ 213 | # Access client related functions 214 | ################################################################################ 215 | */ 216 | 217 | static PyObject * 218 | likwid_hpmmode(PyObject *self, PyObject *args) 219 | { 220 | int mode; 221 | if (!PyArg_ParseTuple(args, "i", &mode)) 222 | return Py_False; 223 | if ((mode == ACCESSMODE_DIRECT) || (mode == ACCESSMODE_DAEMON)) 224 | { 225 | HPMmode(mode); 226 | return Py_True; 227 | } 228 | return Py_False; 229 | } 230 | 231 | static PyObject * 232 | likwid_hpminit(PyObject *self, PyObject *args) 233 | { 234 | int err = HPMinit(); 235 | if (err == 0) 236 | { 237 | access_initialized = 1; 238 | return Py_True; 239 | } 240 | return Py_False; 241 | } 242 | 243 | static PyObject * 244 | likwid_hpmaddthread(PyObject *self, PyObject *args) 245 | { 246 | int cpuid, ret; 247 | if (!PyArg_ParseTuple(args, "i", &cpuid)) 248 | return Py_BuildValue("i", -1); 249 | if (access_initialized == 0) 250 | { 251 | return Py_BuildValue("i", -1); 252 | } 253 | ret = HPMaddThread(cpuid); 254 | return Py_BuildValue("i", ret); 255 | } 256 | 257 | static PyObject * 258 | likwid_hpmfinalize(PyObject *self, PyObject *args) 259 | { 260 | HPMfinalize(); 261 | access_initialized = 0; 262 | Py_RETURN_NONE; 263 | } 264 | 265 | /* 266 | ################################################################################ 267 | # Config file related functions 268 | ################################################################################ 269 | */ 270 | 271 | static PyObject * 272 | likwid_initconfiguration(PyObject *self, PyObject *args) 273 | { 274 | if (config_initialized) 275 | return Py_True; 276 | int ret = init_configuration(); 277 | if (ret == 0) 278 | { 279 | config_initialized = 1; 280 | return Py_True; 281 | } 282 | return Py_False; 283 | } 284 | 285 | static PyObject * 286 | likwid_destroyconfiguration(PyObject *self, PyObject *args) 287 | { 288 | if (!config_initialized) 289 | return Py_False; 290 | int ret = destroy_configuration(); 291 | if (ret == 0) 292 | { 293 | config_initialized = 0; 294 | return Py_True; 295 | } 296 | return Py_False; 297 | } 298 | 299 | static PyObject * 300 | likwid_getconfiguration(PyObject *self, PyObject *args) 301 | { 302 | PyObject *d = PyDict_New(); 303 | if (!config_initialized) 304 | { 305 | int ret = init_configuration(); 306 | if (ret == 0) 307 | { 308 | config_initialized = 1; 309 | configfile = get_configuration(); 310 | } 311 | } 312 | if ((config_initialized) && (configfile == NULL)) 313 | { 314 | configfile = get_configuration(); 315 | } 316 | PyDict_SetItem(d, PYSTR("configFileName"), PYSTR(configfile->configFileName)); 317 | PyDict_SetItem(d, PYSTR("topologyCfgFileName"), PYSTR(configfile->topologyCfgFileName)); 318 | PyDict_SetItem(d, PYSTR("daemonPath"), PYSTR(configfile->daemonPath)); 319 | PyDict_SetItem(d, PYSTR("groupPath"), PYSTR(configfile->groupPath)); 320 | PyDict_SetItem(d, PYSTR("daemonMode"), PYINT(configfile->daemonMode)); 321 | PyDict_SetItem(d, PYSTR("maxNumThreads"), PYINT(configfile->maxNumThreads)); 322 | PyDict_SetItem(d, PYSTR("maxNumNodes"), PYINT(configfile->maxNumNodes)); 323 | return d; 324 | } 325 | 326 | static PyObject * 327 | likwid_setgrouppath(PyObject *self, PyObject *args) 328 | { 329 | int ret = 0; 330 | char* grouppath; 331 | if (!PyArg_ParseTuple(args, "s", &grouppath)) 332 | return Py_False; 333 | ret = config_setGroupPath(grouppath); 334 | if (ret == 0) 335 | { 336 | return Py_True; 337 | } 338 | return Py_False; 339 | } 340 | 341 | /* 342 | ################################################################################ 343 | # CPU topology related functions 344 | ################################################################################ 345 | */ 346 | 347 | static PyObject * 348 | likwid_inittopology(PyObject *self, PyObject *args) 349 | { 350 | int ret = topology_init(); 351 | if (ret == 0) 352 | { 353 | topo_initialized = 1; 354 | return Py_True; 355 | } 356 | return Py_False; 357 | } 358 | 359 | static PyObject * 360 | likwid_finalizetopology(PyObject *self, PyObject *args) 361 | { 362 | topology_finalize(); 363 | topo_initialized = 0; 364 | cputopo = NULL; 365 | cpuinfo = NULL; 366 | Py_RETURN_NONE; 367 | } 368 | 369 | static PyObject * 370 | likwid_getcputopology(PyObject *self, PyObject *args) 371 | { 372 | int i, ret; 373 | PyObject *d = PyDict_New(); 374 | if (!topo_initialized) 375 | { 376 | ret = topology_init(); 377 | if (ret == 0) 378 | { 379 | topo_initialized = 1; 380 | } 381 | else 382 | { 383 | return d; 384 | } 385 | } 386 | PyObject *threads = PyDict_New(); 387 | PyObject *caches = PyDict_New(); 388 | PyObject *tmp; 389 | if ((topo_initialized) && (cputopo == NULL)) 390 | { 391 | cputopo = get_cpuTopology(); 392 | } 393 | if (!numa_initialized) 394 | { 395 | if (numa_init() == 0) 396 | { 397 | numa_initialized = 1; 398 | numainfo = get_numaTopology(); 399 | } 400 | } 401 | if ((numa_initialized) && (numainfo == NULL)) 402 | { 403 | numainfo = get_numaTopology(); 404 | } 405 | PyDict_SetItem(d, PYSTR("numHWThreads"), PYINT(cputopo->numHWThreads)); 406 | PyDict_SetItem(d, PYSTR("activeHWThreads"), PYINT(cputopo->activeHWThreads)); 407 | PyDict_SetItem(d, PYSTR("numSockets"), PYINT(cputopo->numSockets)); 408 | PyDict_SetItem(d, PYSTR("numCoresPerSocket"), PYINT(cputopo->numCoresPerSocket)); 409 | PyDict_SetItem(d, PYSTR("numThreadsPerCore"), PYINT(cputopo->numThreadsPerCore)); 410 | PyDict_SetItem(d, PYSTR("numCacheLevels"), PYINT(cputopo->numCacheLevels)); 411 | for (i = 0; i < (int)cputopo->numHWThreads; i++) 412 | { 413 | tmp = PyDict_New(); 414 | PyDict_SetItem(tmp, PYSTR("threadId"), PYUINT(cputopo->threadPool[i].threadId)); 415 | PyDict_SetItem(tmp, PYSTR("coreId"), PYUINT(cputopo->threadPool[i].coreId)); 416 | PyDict_SetItem(tmp, PYSTR("packageId"), PYUINT(cputopo->threadPool[i].packageId)); 417 | PyDict_SetItem(tmp, PYSTR("apicId"), PYUINT(cputopo->threadPool[i].apicId)); 418 | PyDict_SetItem(threads, PYINT(i), tmp); 419 | } 420 | PyDict_SetItem(d, PYSTR("threadPool"), threads); 421 | for (i = 0; i < (int)cputopo->numCacheLevels; i++) 422 | { 423 | tmp = PyDict_New(); 424 | PyDict_SetItem(tmp, PYSTR("level"), PYUINT(cputopo->cacheLevels[i].level)); 425 | PyDict_SetItem(tmp, PYSTR("associativity"), PYUINT(cputopo->cacheLevels[i].associativity)); 426 | PyDict_SetItem(tmp, PYSTR("sets"), PYUINT(cputopo->cacheLevels[i].sets)); 427 | PyDict_SetItem(tmp, PYSTR("lineSize"), PYUINT(cputopo->cacheLevels[i].lineSize)); 428 | PyDict_SetItem(tmp, PYSTR("size"), PYUINT(cputopo->cacheLevels[i].size)); 429 | PyDict_SetItem(tmp, PYSTR("threads"), PYUINT(cputopo->cacheLevels[i].threads)); 430 | PyDict_SetItem(tmp, PYSTR("inclusive"), PYUINT(cputopo->cacheLevels[i].inclusive)); 431 | switch(cputopo->cacheLevels[i].type) 432 | { 433 | case DATACACHE: 434 | PyDict_SetItem(tmp, PYSTR("type"), PYSTR("data")); 435 | break; 436 | case INSTRUCTIONCACHE: 437 | PyDict_SetItem(tmp, PYSTR("type"), PYSTR("instruction")); 438 | break; 439 | case UNIFIEDCACHE: 440 | PyDict_SetItem(tmp, PYSTR("type"), PYSTR("unified")); 441 | break; 442 | case ITLB: 443 | PyDict_SetItem(tmp, PYSTR("type"), PYSTR("itlb")); 444 | break; 445 | case DTLB: 446 | PyDict_SetItem(tmp, PYSTR("type"), PYSTR("dtlb")); 447 | break; 448 | case NOCACHE: 449 | break; 450 | } 451 | PyDict_SetItem(caches, PYUINT(cputopo->cacheLevels[i].level), tmp); 452 | } 453 | PyDict_SetItem(d, PYSTR("cacheLevels"), caches); 454 | return d; 455 | } 456 | 457 | static PyObject * 458 | likwid_getcpuinfo(PyObject *self, PyObject *args) 459 | { 460 | int ret; 461 | PyObject *d = PyDict_New(); 462 | if (!topo_initialized) 463 | { 464 | ret = topology_init(); 465 | if (ret == 0) 466 | { 467 | topo_initialized = 1; 468 | } 469 | else 470 | { 471 | return d; 472 | } 473 | } 474 | if ((topo_initialized) && (cputopo == NULL)) 475 | { 476 | cputopo = get_cpuTopology(); 477 | } 478 | if (!numa_initialized) 479 | { 480 | if (numa_init() == 0) 481 | { 482 | numa_initialized = 1; 483 | numainfo = get_numaTopology(); 484 | } 485 | } 486 | if ((numa_initialized) && (numainfo == NULL)) 487 | { 488 | numainfo = get_numaTopology(); 489 | } 490 | CpuInfo_t info = get_cpuInfo(); 491 | PyDict_SetItem(d, PYSTR("family"), PYUINT(info->family)); 492 | PyDict_SetItem(d, PYSTR("model"), PYUINT(info->model)); 493 | PyDict_SetItem(d, PYSTR("stepping"), PYUINT(info->stepping)); 494 | PyDict_SetItem(d, PYSTR("clock"), Py_BuildValue("k", info->clock)); 495 | if (info->turbo) 496 | { 497 | PyDict_SetItem(d, PYSTR("turbo"), Py_True); 498 | } 499 | else 500 | { 501 | PyDict_SetItem(d, PYSTR("turbo"), Py_False); 502 | } 503 | if (info->isIntel) 504 | { 505 | PyDict_SetItem(d, PYSTR("isIntel"), Py_True); 506 | } 507 | else 508 | { 509 | PyDict_SetItem(d, PYSTR("isIntel"), Py_False); 510 | } 511 | if (info->supportUncore) 512 | { 513 | PyDict_SetItem(d, PYSTR("supportUncore"), Py_True); 514 | } 515 | else 516 | { 517 | PyDict_SetItem(d, PYSTR("supportUncore"), Py_False); 518 | } 519 | PyDict_SetItem(d, PYSTR("osname"), PYSTR(info->osname)); 520 | PyDict_SetItem(d, PYSTR("name"), PYSTR(info->name)); 521 | PyDict_SetItem(d, PYSTR("short_name"), PYSTR(info->short_name)); 522 | PyDict_SetItem(d, PYSTR("features"), PYSTR(info->features)); 523 | PyDict_SetItem(d, PYSTR("featureFlags"), PYUINT(info->featureFlags)); 524 | PyDict_SetItem(d, PYSTR("perf_version"), PYUINT(info->perf_version)); 525 | PyDict_SetItem(d, PYSTR("perf_num_ctr"), PYUINT(info->perf_num_ctr)); 526 | PyDict_SetItem(d, PYSTR("perf_width_ctr"), PYUINT(info->perf_width_ctr)); 527 | PyDict_SetItem(d, PYSTR("perf_num_fixed_ctr"), PYUINT(info->perf_num_fixed_ctr)); 528 | #if (LIKWID_MAJOR == 5) 529 | PyDict_SetItem(d, PYSTR("architecture"), PYSTR(info->architecture)); 530 | #endif 531 | return d; 532 | } 533 | 534 | 535 | static PyObject * 536 | likwid_printsupportedcpus(PyObject *self, PyObject *args) 537 | { 538 | print_supportedCPUs(); 539 | Py_RETURN_NONE; 540 | } 541 | 542 | /* 543 | ################################################################################ 544 | # NUMA related functions 545 | ################################################################################ 546 | */ 547 | 548 | static PyObject * 549 | likwid_initnuma(PyObject *self, PyObject *args) 550 | { 551 | int i,j; 552 | if (!topo_initialized) 553 | { 554 | topology_init(); 555 | topo_initialized = 1; 556 | cpuinfo = get_cpuInfo(); 557 | cputopo = get_cpuTopology(); 558 | } 559 | if ((topo_initialized) && (cpuinfo == NULL)) 560 | { 561 | cpuinfo = get_cpuInfo(); 562 | } 563 | if ((topo_initialized) && (cputopo == NULL)) 564 | { 565 | cputopo = get_cpuTopology(); 566 | } 567 | if (numa_initialized == 0) 568 | { 569 | if (numa_init() == 0) 570 | { 571 | numa_initialized = 1; 572 | numainfo = get_numaTopology(); 573 | } 574 | else 575 | { 576 | PyObject *d = PyDict_New(); 577 | PyDict_SetItem(d, PYSTR("numberOfNodes"), PYINT(0)); 578 | PyDict_SetItem(d, PYSTR("nodes"), PyDict_New()); 579 | return d; 580 | } 581 | } 582 | if ((numa_initialized) && (numainfo == NULL)) 583 | { 584 | numainfo = get_numaTopology(); 585 | } 586 | if (affinity_initialized == 0) 587 | { 588 | affinity_init(); 589 | affinity_initialized = 1; 590 | affinity = get_affinityDomains(); 591 | } 592 | if ((affinity_initialized) && (affinity == NULL)) 593 | { 594 | affinity = get_affinityDomains(); 595 | } 596 | PyObject *d = PyDict_New(); 597 | PyObject *nodes = PyDict_New(); 598 | PyDict_SetItem(d, PYSTR("numberOfNodes"), PYINT(numainfo->numberOfNodes)); 599 | for(i = 0;i < (int)numainfo->numberOfNodes; i++) 600 | { 601 | PyObject *n = PyDict_New(); 602 | PyDict_SetItem(n, PYSTR("id"), PYINT(numainfo->nodes[i].id)); 603 | PyDict_SetItem(n, PYSTR("totalMemory"), PYINT(numainfo->nodes[i].totalMemory)); 604 | PyDict_SetItem(n, PYSTR("freeMemory"), PYINT(numainfo->nodes[i].freeMemory)); 605 | PyDict_SetItem(n, PYSTR("numberOfProcessors"), PYINT(numainfo->nodes[i].numberOfProcessors)); 606 | PyDict_SetItem(n, PYSTR("numberOfDistances"), PYINT(numainfo->nodes[i].numberOfDistances)); 607 | PyObject *l = PyList_New(numainfo->nodes[i].numberOfProcessors); 608 | for(j = 0; j < (int)numainfo->nodes[i].numberOfProcessors; j++) 609 | { 610 | PyList_SET_ITEM(l, (Py_ssize_t)j, PYINT(numainfo->nodes[i].processors[j])); 611 | } 612 | PyDict_SetItem(n, PYSTR("processors"), l); 613 | PyObject *dist = PyList_New(numainfo->nodes[i].numberOfDistances); 614 | for(j = 0; j < (int)numainfo->nodes[i].numberOfDistances; j++) 615 | { 616 | PyList_SET_ITEM(dist, (Py_ssize_t)j, PYINT(numainfo->nodes[i].distances[j])); 617 | } 618 | PyDict_SetItem(n, PYSTR("distances"), dist); 619 | PyDict_SetItem(nodes, PYINT(i), n); 620 | } 621 | PyDict_SetItem(d, PYSTR("nodes"), nodes); 622 | return d; 623 | } 624 | 625 | static PyObject * 626 | likwid_finalizenuma(PyObject *self, PyObject *args) 627 | { 628 | if (numa_initialized) 629 | { 630 | numa_finalize(); 631 | numainfo = NULL; 632 | numa_initialized = 0; 633 | } 634 | Py_RETURN_NONE; 635 | } 636 | 637 | 638 | /* 639 | ################################################################################ 640 | # Affinity related functions 641 | ################################################################################ 642 | */ 643 | 644 | static PyObject * 645 | likwid_initaffinity(PyObject *self, PyObject *args) 646 | { 647 | int i,j; 648 | 649 | if (topo_initialized == 0) 650 | { 651 | topology_init(); 652 | topo_initialized = 1; 653 | cpuinfo = get_cpuInfo(); 654 | cputopo = get_cpuTopology(); 655 | } 656 | if ((topo_initialized) && (cpuinfo == NULL)) 657 | { 658 | cpuinfo = get_cpuInfo(); 659 | } 660 | if ((topo_initialized) && (cputopo == NULL)) 661 | { 662 | cputopo = get_cpuTopology(); 663 | } 664 | if (numa_initialized == 0) 665 | { 666 | if (numa_init() == 0) 667 | { 668 | numa_initialized = 1; 669 | numainfo = get_numaTopology(); 670 | } 671 | } 672 | if ((numa_initialized) && (numainfo == NULL)) 673 | { 674 | numainfo = get_numaTopology(); 675 | } 676 | if (affinity_initialized == 0) 677 | { 678 | affinity_init(); 679 | affinity_initialized = 1; 680 | affinity = get_affinityDomains(); 681 | } 682 | if ((affinity_initialized) && (affinity == NULL)) 683 | { 684 | affinity = get_affinityDomains(); 685 | } 686 | PyObject *n = PyDict_New(); 687 | if (affinity == NULL) 688 | { 689 | return n; 690 | } 691 | PyDict_SetItem(n, PYSTR("numberOfAffinityDomains"), PYINT(affinity->numberOfAffinityDomains)); 692 | PyDict_SetItem(n, PYSTR("numberOfSocketDomains"), PYINT(affinity->numberOfSocketDomains)); 693 | PyDict_SetItem(n, PYSTR("numberOfNumaDomains"), PYINT(affinity->numberOfNumaDomains)); 694 | PyDict_SetItem(n, PYSTR("numberOfProcessorsPerSocket"), PYINT(affinity->numberOfProcessorsPerSocket)); 695 | PyDict_SetItem(n, PYSTR("numberOfCacheDomains"), PYINT(affinity->numberOfCacheDomains)); 696 | PyDict_SetItem(n, PYSTR("numberOfCoresPerCache"), PYINT(affinity->numberOfCoresPerCache)); 697 | PyDict_SetItem(n, PYSTR("numberOfProcessorsPerCache"), PYINT(affinity->numberOfProcessorsPerCache)); 698 | PyObject *doms = PyDict_New(); 699 | for(i = 0; i < (int)affinity->numberOfAffinityDomains; i++) 700 | { 701 | PyObject *a = PyDict_New(); 702 | #if (LIKWID_MAJOR == 5 && LIKWID_RELEASE >= 4) 703 | PyDict_SetItem(a, PYSTR("tag"), PYSTR(affinity->domains[i].tag)); 704 | #else 705 | PyDict_SetItem(a, PYSTR("tag"), PYSTR(bdata(affinity->domains[i].tag))); 706 | #endif 707 | PyDict_SetItem(a, PYSTR("numberOfProcessors"), PYINT(affinity->domains[i].numberOfProcessors)); 708 | PyDict_SetItem(a, PYSTR("numberOfCores"), PYINT(affinity->domains[i].numberOfCores)); 709 | PyObject *l = PyList_New(affinity->domains[i].numberOfProcessors); 710 | for(j = 0;j < (int)affinity->domains[i].numberOfProcessors; j++) 711 | { 712 | PyList_SET_ITEM(l, (Py_ssize_t)j, PYINT(affinity->domains[i].processorList[j])); 713 | } 714 | PyDict_SetItem(a, PYSTR("processorList"), l); 715 | PyDict_SetItem(doms, PYINT(i), a); 716 | } 717 | PyDict_SetItem(n, PYSTR("domains"), doms); 718 | return n; 719 | } 720 | 721 | static PyObject * 722 | likwid_finalizeaffinity(PyObject *self, PyObject *args) 723 | { 724 | if (affinity_initialized) 725 | { 726 | affinity_finalize(); 727 | affinity_initialized = 0; 728 | affinity = NULL; 729 | } 730 | Py_RETURN_NONE; 731 | } 732 | 733 | static PyObject * 734 | likwid_cpustr_to_cpulist(PyObject *self, PyObject *args) 735 | { 736 | int ret = 0, j = 0; 737 | const char *cpustr; 738 | if (!PyArg_ParseTuple(args, "s", &cpustr)) 739 | { 740 | Py_RETURN_NONE; 741 | } 742 | if (configfile == NULL) 743 | { 744 | init_configuration(); 745 | configfile = get_configuration(); 746 | } 747 | int* cpulist = (int*) malloc(configfile->maxNumThreads * sizeof(int)); 748 | if (!cpulist) 749 | { 750 | Py_RETURN_NONE; 751 | } 752 | ret = cpustr_to_cpulist((char *)cpustr, cpulist, configfile->maxNumThreads); 753 | if (ret < 0) 754 | { 755 | free(cpulist); 756 | Py_RETURN_NONE; 757 | } 758 | PyObject *l = PyList_New(ret); 759 | for(j=0;jmaxNumThreads * sizeof(int)); 784 | if (!gpulist) 785 | { 786 | Py_RETURN_NONE; 787 | } 788 | ret = gpustr_to_gpulist((char *)gpustr, gpulist, configfile->maxNumThreads); 789 | if (ret < 0) 790 | { 791 | free(gpulist); 792 | Py_RETURN_NONE; 793 | } 794 | PyObject *l = PyList_New(ret); 795 | for(j=0;jbaseFrequency)); 952 | PyDict_SetItem(n, PYSTR("minFrequency"), Py_BuildValue("d", power->minFrequency)); 953 | PyDict_SetItem(n, PYSTR("powerUnit"), Py_BuildValue("d", power->powerUnit)); 954 | PyDict_SetItem(n, PYSTR("timeUnit"), Py_BuildValue("d", power->timeUnit)); 955 | 956 | PyObject *l = PyList_New(power->turbo.numSteps); 957 | for (i=0; iturbo.numSteps; i++) 958 | { 959 | PyList_SET_ITEM(l, (Py_ssize_t)i, Py_BuildValue("d", power->turbo.steps[i])); 960 | } 961 | PyDict_SetItem(n, PYSTR("turbo"), l); 962 | PyObject *d = PyDict_New(); 963 | for(i=0;idomains[i].type)); 967 | PyDict_SetItem(pd, PYSTR("energyUnit"), Py_BuildValue("d", power->domains[i].energyUnit)); 968 | if (power->domains[i].supportFlags & POWER_DOMAIN_SUPPORT_STATUS) 969 | { 970 | PyDict_SetItem(pd, PYSTR("supportStatus"), Py_True); 971 | } 972 | else 973 | { 974 | PyDict_SetItem(pd, PYSTR("supportStatus"), Py_False); 975 | } 976 | if (power->domains[i].supportFlags & POWER_DOMAIN_SUPPORT_PERF) 977 | { 978 | PyDict_SetItem(pd, PYSTR("supportPerf"), Py_True); 979 | } 980 | else 981 | { 982 | PyDict_SetItem(pd, PYSTR("supportPerf"), Py_False); 983 | } 984 | if (power->domains[i].supportFlags & POWER_DOMAIN_SUPPORT_POLICY) 985 | { 986 | PyDict_SetItem(pd, PYSTR("supportPolicy"), Py_True); 987 | } 988 | else 989 | { 990 | PyDict_SetItem(pd, PYSTR("supportPolicy"), Py_False); 991 | } 992 | if (power->domains[i].supportFlags & POWER_DOMAIN_SUPPORT_LIMIT) 993 | { 994 | PyDict_SetItem(pd, PYSTR("supportLimit"), Py_True); 995 | } 996 | else 997 | { 998 | PyDict_SetItem(pd, PYSTR("supportLimit"), Py_False); 999 | } 1000 | if (power->domains[i].supportFlags & POWER_DOMAIN_SUPPORT_INFO) 1001 | { 1002 | PyDict_SetItem(pd, PYSTR("supportInfo"), Py_True); 1003 | PyDict_SetItem(pd, PYSTR("tdp"), Py_BuildValue("d", power->domains[i].tdp)); 1004 | PyDict_SetItem(pd, PYSTR("minPower"), Py_BuildValue("d", power->domains[i].minPower)); 1005 | PyDict_SetItem(pd, PYSTR("maxPower"), Py_BuildValue("d", power->domains[i].maxPower)); 1006 | PyDict_SetItem(pd, PYSTR("maxTimeWindow"), Py_BuildValue("d", power->domains[i].maxTimeWindow)); 1007 | } 1008 | else 1009 | { 1010 | PyDict_SetItem(pd, PYSTR("supportInfo"), Py_False); 1011 | } 1012 | PyDict_SetItem(d, PYSTR(power_names[i]), pd); 1013 | } 1014 | PyDict_SetItem(n, PYSTR("domains"), d); 1015 | return n; 1016 | } 1017 | 1018 | 1019 | static PyObject * 1020 | likwid_putPowerInfo(PyObject *self, PyObject *args) 1021 | { 1022 | if (power_initialized) 1023 | { 1024 | power_finalize(); 1025 | power_initialized = 0; 1026 | power = NULL; 1027 | } 1028 | Py_RETURN_NONE; 1029 | } 1030 | 1031 | static PyObject * 1032 | likwid_startPower(PyObject *self, PyObject *args) 1033 | { 1034 | PowerData pwrdata; 1035 | pwrdata.before = 0; 1036 | int cpuId; 1037 | PowerType type; 1038 | if (PyArg_ParseTuple(args, "iI", &cpuId, &type)) 1039 | { 1040 | pwrdata.domain = type; 1041 | power_start(&pwrdata, cpuId, type); 1042 | } 1043 | return Py_BuildValue("I", pwrdata.before); 1044 | } 1045 | 1046 | static PyObject * 1047 | likwid_stopPower(PyObject *self, PyObject *args) 1048 | { 1049 | PowerData pwrdata; 1050 | pwrdata.after = 0; 1051 | int cpuId; 1052 | PowerType type; 1053 | if (PyArg_ParseTuple(args, "iI", &cpuId, &type)) 1054 | { 1055 | pwrdata.domain = type; 1056 | power_stop(&pwrdata, cpuId, type); 1057 | } 1058 | return Py_BuildValue("I", pwrdata.after); 1059 | } 1060 | 1061 | static PyObject * 1062 | likwid_getPower(PyObject *self, PyObject *args) 1063 | { 1064 | PowerData pwrdata; 1065 | double energy = 0.0; 1066 | pwrdata.before = 0; 1067 | pwrdata.after = 0; 1068 | if (PyArg_ParseTuple(args, "III", &pwrdata.before, &pwrdata.after, &pwrdata.domain)) 1069 | { 1070 | energy = power_printEnergy(&pwrdata); 1071 | } 1072 | return Py_BuildValue("d", energy); 1073 | } 1074 | 1075 | /* 1076 | ################################################################################ 1077 | # Perfmon related functions 1078 | ################################################################################ 1079 | */ 1080 | 1081 | static PyObject * 1082 | likwid_init(PyObject *self, PyObject *args) 1083 | { 1084 | int ret, i; 1085 | int nrThreads = 0; 1086 | PyObject * pyList; 1087 | 1088 | if (topo_initialized == 0) 1089 | { 1090 | topology_init(); 1091 | topo_initialized = 1; 1092 | cpuinfo = get_cpuInfo(); 1093 | cputopo = get_cpuTopology(); 1094 | } 1095 | if ((topo_initialized) && (cpuinfo == NULL)) 1096 | { 1097 | cpuinfo = get_cpuInfo(); 1098 | } 1099 | if ((topo_initialized) && (cputopo == NULL)) 1100 | { 1101 | cputopo = get_cpuTopology(); 1102 | } 1103 | if (numa_initialized == 0) 1104 | { 1105 | numa_init(); 1106 | numa_initialized = 1; 1107 | numainfo = get_numaTopology(); 1108 | } 1109 | if ((numa_initialized) && (numainfo == NULL)) 1110 | { 1111 | numainfo = get_numaTopology(); 1112 | } 1113 | ret = PyArg_ParseTuple(args, "O!", &PyList_Type, &pyList); 1114 | if (pyList == NULL || ret == 0) 1115 | { 1116 | printf("No or wrong function argument: List required\n"); 1117 | return PYINT(1); 1118 | } 1119 | if (!PyList_Check(pyList)) 1120 | { 1121 | printf("Function argument is no list\n"); 1122 | return PYINT(1); 1123 | } 1124 | nrThreads = PyList_Size(pyList); 1125 | int * cpulist = malloc(nrThreads * sizeof(int)); 1126 | if (!cpulist) 1127 | { 1128 | printf("Cannot allocate space for cpu list\n"); 1129 | return PYINT(1); 1130 | } 1131 | for (i=0; i 0 && PyArg_ParseTuple(args, "i", &ret)) 1230 | { 1231 | ret = perfmon_readCountersCpu(ret); 1232 | } 1233 | return PYINT(ret); 1234 | } 1235 | 1236 | static PyObject * 1237 | likwid_readGroupCounters(PyObject *self, PyObject *args) 1238 | { 1239 | int ret = -1; 1240 | if (perfmon_initialized > 0 && PyArg_ParseTuple(args, "i", &ret)) 1241 | { 1242 | ret = perfmon_readGroupCounters(ret); 1243 | } 1244 | return PYINT(ret); 1245 | } 1246 | 1247 | static PyObject * 1248 | likwid_readGroupThreadCounters(PyObject *self, PyObject *args) 1249 | { 1250 | int ret = -1; 1251 | int thread = 0; 1252 | if (perfmon_initialized > 0 && PyArg_ParseTuple(args, "ii", &ret, &thread)) 1253 | { 1254 | ret = perfmon_readGroupThreadCounters(ret, thread); 1255 | } 1256 | return PYINT(ret); 1257 | } 1258 | 1259 | static PyObject * 1260 | likwid_switchGroup(PyObject *self, PyObject *args) 1261 | { 1262 | int ret = -1; 1263 | int newgroup = 0; 1264 | if (perfmon_initialized > 0 && PyArg_ParseTuple(args, "i", &newgroup)) 1265 | { 1266 | if (newgroup >= perfmon_getNumberOfGroups()) 1267 | { 1268 | newgroup = 0; 1269 | } 1270 | if (newgroup != perfmon_getIdOfActiveGroup()) 1271 | { 1272 | ret = perfmon_switchActiveGroup(newgroup); 1273 | } 1274 | } 1275 | return PYINT(ret); 1276 | } 1277 | 1278 | static PyObject * 1279 | likwid_finalize(PyObject *self, PyObject *args) 1280 | { 1281 | if (perfmon_initialized == 1) 1282 | { 1283 | perfmon_finalize(); 1284 | perfmon_initialized = 0; 1285 | } 1286 | if (affinity_initialized == 1) 1287 | { 1288 | affinity_finalize(); 1289 | affinity_initialized = 0; 1290 | affinity = NULL; 1291 | } 1292 | if (numa_initialized == 1) 1293 | { 1294 | numa_finalize(); 1295 | numa_initialized = 0; 1296 | numainfo = NULL; 1297 | } 1298 | if (topo_initialized == 1) 1299 | { 1300 | topology_finalize(); 1301 | topo_initialized = 0; 1302 | cputopo = NULL; 1303 | cpuinfo = NULL; 1304 | } 1305 | if (config_initialized == 1) 1306 | { 1307 | destroy_configuration(); 1308 | config_initialized = 0; 1309 | configfile = NULL; 1310 | } 1311 | return PYINT(0); 1312 | } 1313 | 1314 | static PyObject * 1315 | likwid_getResult(PyObject *self, PyObject *args) 1316 | { 1317 | int g, e, t; 1318 | double result = NAN; 1319 | if (PyArg_ParseTuple(args, "iii", &g, &e, &t)) 1320 | { 1321 | result = perfmon_getResult(g, e, t); 1322 | } 1323 | return Py_BuildValue("d", result); 1324 | } 1325 | 1326 | static PyObject * 1327 | likwid_getLastResult(PyObject *self, PyObject *args) 1328 | { 1329 | int g, e, t; 1330 | double result = NAN; 1331 | if (PyArg_ParseTuple(args, "iii", &g, &e, &t)) 1332 | { 1333 | result = perfmon_getLastResult(g, e, t); 1334 | } 1335 | return Py_BuildValue("d", result); 1336 | } 1337 | 1338 | static PyObject * 1339 | likwid_getMetric(PyObject *self, PyObject *args) 1340 | { 1341 | int g, m, t; 1342 | double result = NAN; 1343 | if (PyArg_ParseTuple(args, "iii", &g, &m, &t)) 1344 | { 1345 | result = perfmon_getMetric(g, m, t); 1346 | } 1347 | return Py_BuildValue("d", result); 1348 | } 1349 | 1350 | static PyObject * 1351 | likwid_getLastMetric(PyObject *self, PyObject *args) 1352 | { 1353 | int g, m, t; 1354 | double result = NAN; 1355 | if (PyArg_ParseTuple(args, "iii", &g, &m, &t)) 1356 | { 1357 | result = perfmon_getLastMetric(g, m, t); 1358 | } 1359 | return Py_BuildValue("d", result); 1360 | } 1361 | 1362 | static PyObject * 1363 | likwid_getNumberOfGroups(PyObject *self, PyObject *args) 1364 | { 1365 | if (perfmon_initialized == 0) 1366 | { 1367 | return 0; 1368 | } 1369 | return PYINT(perfmon_getNumberOfGroups()); 1370 | } 1371 | 1372 | static PyObject * 1373 | likwid_getIdOfActiveGroup(PyObject *self, PyObject *args) 1374 | { 1375 | if (perfmon_initialized == 0) 1376 | { 1377 | return 0; 1378 | } 1379 | return PYINT(perfmon_getIdOfActiveGroup()); 1380 | } 1381 | 1382 | static PyObject * 1383 | likwid_getNumberOfThreads(PyObject *self, PyObject *args) 1384 | { 1385 | if (perfmon_initialized == 0) 1386 | { 1387 | return 0; 1388 | } 1389 | return PYINT(perfmon_getNumberOfThreads()); 1390 | } 1391 | 1392 | static PyObject * 1393 | likwid_getTimeOfGroup(PyObject *self, PyObject *args) 1394 | { 1395 | if (perfmon_initialized == 0) 1396 | { 1397 | return 0; 1398 | } 1399 | int groupId; 1400 | double time = 0.0; 1401 | if (PyArg_ParseTuple(args, "i", &groupId)) 1402 | { 1403 | time = perfmon_getTimeOfGroup(groupId); 1404 | } 1405 | return Py_BuildValue("d", time); 1406 | } 1407 | 1408 | static PyObject * 1409 | likwid_getNumberOfEvents(PyObject *self, PyObject *args) 1410 | { 1411 | if (perfmon_initialized == 0) 1412 | { 1413 | return 0; 1414 | } 1415 | int groupId; 1416 | int num_events = 0; 1417 | if (PyArg_ParseTuple(args, "i", &groupId)) 1418 | { 1419 | num_events = perfmon_getNumberOfEvents(groupId); 1420 | } 1421 | return PYINT(num_events); 1422 | } 1423 | 1424 | static PyObject * 1425 | likwid_getNumberOfMetrics(PyObject *self, PyObject *args) 1426 | { 1427 | if (perfmon_initialized == 0) 1428 | { 1429 | return 0; 1430 | } 1431 | int groupId; 1432 | int num_metrics = 0; 1433 | if (PyArg_ParseTuple(args, "i", &groupId)) 1434 | { 1435 | num_metrics = perfmon_getNumberOfMetrics(groupId); 1436 | } 1437 | return PYINT(num_metrics); 1438 | } 1439 | 1440 | static PyObject * 1441 | likwid_getNameOfEvent(PyObject *self, PyObject *args) 1442 | { 1443 | if (perfmon_initialized == 0) 1444 | { 1445 | return 0; 1446 | } 1447 | int g, e; 1448 | char* name = NULL; 1449 | if (PyArg_ParseTuple(args, "ii", &g, &e)) 1450 | { 1451 | name = perfmon_getEventName(g,e); 1452 | } 1453 | return PYSTR(name); 1454 | } 1455 | 1456 | static PyObject * 1457 | likwid_getNameOfCounter(PyObject *self, PyObject *args) 1458 | { 1459 | if (perfmon_initialized == 0) 1460 | { 1461 | return 0; 1462 | } 1463 | int g, c; 1464 | char* name = NULL; 1465 | if (PyArg_ParseTuple(args, "ii", &g, &c)) 1466 | { 1467 | name = perfmon_getCounterName(g,c); 1468 | } 1469 | return PYSTR(name); 1470 | } 1471 | 1472 | static PyObject * 1473 | likwid_getNameOfMetric(PyObject *self, PyObject *args) 1474 | { 1475 | if (perfmon_initialized == 0) 1476 | { 1477 | return 0; 1478 | } 1479 | int g, m; 1480 | char* name = NULL; 1481 | if (PyArg_ParseTuple(args, "ii", &g, &m)) 1482 | { 1483 | name = perfmon_getMetricName(g, m); 1484 | } 1485 | return PYSTR(name); 1486 | } 1487 | 1488 | static PyObject * 1489 | likwid_getNameOfGroup(PyObject *self, PyObject *args) 1490 | { 1491 | if (perfmon_initialized == 0) 1492 | { 1493 | return 0; 1494 | } 1495 | int groupId; 1496 | char* name = NULL; 1497 | if (PyArg_ParseTuple(args, "i", &groupId)) 1498 | { 1499 | name = perfmon_getGroupName(groupId); 1500 | } 1501 | return PYSTR(name); 1502 | } 1503 | 1504 | static PyObject * 1505 | likwid_getShortInfoOfGroup(PyObject *self, PyObject *args) 1506 | { 1507 | if (perfmon_initialized == 0) 1508 | { 1509 | return 0; 1510 | } 1511 | int groupId; 1512 | char* info = NULL; 1513 | if (PyArg_ParseTuple(args, "i", &groupId)) 1514 | { 1515 | info = perfmon_getGroupInfoShort(groupId); 1516 | } 1517 | return PYSTR(info); 1518 | } 1519 | 1520 | static PyObject * 1521 | likwid_getLongInfoOfGroup(PyObject *self, PyObject *args) 1522 | { 1523 | if (perfmon_initialized == 0) 1524 | { 1525 | return 0; 1526 | } 1527 | int groupId; 1528 | char* info = NULL; 1529 | if (PyArg_ParseTuple(args, "i", &groupId)) 1530 | { 1531 | info = perfmon_getGroupInfoLong(groupId); 1532 | } 1533 | return PYSTR(info); 1534 | } 1535 | 1536 | static PyObject * 1537 | likwid_getGroups(PyObject *self, PyObject *args) 1538 | { 1539 | int i, ret; 1540 | char** tmp, **infos, **longs; 1541 | PyObject *l; 1542 | if (topo_initialized == 0) 1543 | { 1544 | topology_init(); 1545 | topo_initialized = 1; 1546 | } 1547 | ret = perfmon_getGroups(&tmp, &infos, &longs); 1548 | if (ret > 0) 1549 | { 1550 | l = PyList_New(ret); 1551 | for(i=0;inumHWThreads * sizeof(int)); 1666 | if (cpulist == NULL) 1667 | { 1668 | return PyList_New(0); 1669 | } 1670 | ret = perfmon_getCpulistOfRegion(r, cputopo->numHWThreads, cpulist); 1671 | PyObject *l = PyList_New(ret); 1672 | for(r=0; rnumDevices); 1925 | for(i = 0; i < gputopo->numDevices; i++) 1926 | { 1927 | GpuDevice* dev = &gputopo->devices[i]; 1928 | PyObject *d = PyDict_New(); 1929 | 1930 | PyDict_SetItem(d, PYSTR("devid"), PYUINT(dev->devid)); 1931 | PyDict_SetItem(d, PYSTR("numaNode"), PYUINT(dev->numaNode)); 1932 | PyDict_SetItem(d, PYSTR("name"), PYSTR(dev->name)); 1933 | PyDict_SetItem(d, PYSTR("mem"), PYUINT(dev->mem)); 1934 | PyDict_SetItem(d, PYSTR("ccapMajor"), PYUINT(dev->ccapMajor)); 1935 | PyDict_SetItem(d, PYSTR("ccapMinor"), PYUINT(dev->ccapMinor)); 1936 | PyDict_SetItem(d, PYSTR("maxThreadsPerBlock"), PYUINT(dev->maxThreadsPerBlock)); 1937 | PyDict_SetItem(d, PYSTR("sharedMemPerBlock"), PYUINT(dev->sharedMemPerBlock)); 1938 | PyDict_SetItem(d, PYSTR("totalConstantMemory"), PYUINT(dev->totalConstantMemory)); 1939 | PyDict_SetItem(d, PYSTR("simdWidth"), PYUINT(dev->simdWidth)); 1940 | PyDict_SetItem(d, PYSTR("memPitch"), PYUINT(dev->memPitch)); 1941 | PyDict_SetItem(d, PYSTR("regsPerBlock"), PYUINT(dev->regsPerBlock)); 1942 | PyDict_SetItem(d, PYSTR("clockRatekHz"), PYUINT(dev->clockRatekHz)); 1943 | PyDict_SetItem(d, PYSTR("textureAlign"), PYUINT(dev->textureAlign)); 1944 | PyDict_SetItem(d, PYSTR("l2Size"), PYUINT(dev->l2Size)); 1945 | PyDict_SetItem(d, PYSTR("memClockRatekHz"), PYUINT(dev->memClockRatekHz)); 1946 | PyDict_SetItem(d, PYSTR("pciBus"), PYUINT(dev->pciBus)); 1947 | PyDict_SetItem(d, PYSTR("pciDev"), PYUINT(dev->pciDev)); 1948 | PyDict_SetItem(d, PYSTR("pciDom"), PYUINT(dev->pciDom)); 1949 | PyDict_SetItem(d, PYSTR("maxBlockRegs"), PYUINT(dev->maxBlockRegs)); 1950 | PyDict_SetItem(d, PYSTR("numMultiProcs"), PYUINT(dev->numMultiProcs)); 1951 | PyDict_SetItem(d, PYSTR("maxThreadPerMultiProc"), PYUINT(dev->maxThreadPerMultiProc)); 1952 | PyDict_SetItem(d, PYSTR("memBusWidth"), PYUINT(dev->memBusWidth)); 1953 | PyDict_SetItem(d, PYSTR("unifiedAddrSpace"), PYUINT(dev->unifiedAddrSpace)); 1954 | PyDict_SetItem(d, PYSTR("ecc"), PYUINT(dev->ecc)); 1955 | PyDict_SetItem(d, PYSTR("asyncEngines"), PYUINT(dev->asyncEngines)); 1956 | PyDict_SetItem(d, PYSTR("mapHostMem"), PYUINT(dev->mapHostMem)); 1957 | PyDict_SetItem(d, PYSTR("integrated"), PYUINT(dev->integrated)); 1958 | 1959 | PyObject *maxThreadsDim = PyList_New(3); 1960 | PyList_SET_ITEM(maxThreadsDim, 0, PYUINT(dev->maxThreadsDim[0])); 1961 | PyList_SET_ITEM(maxThreadsDim, 1, PYUINT(dev->maxThreadsDim[1])); 1962 | PyList_SET_ITEM(maxThreadsDim, 2, PYUINT(dev->maxThreadsDim[2])); 1963 | PyDict_SetItem(d, PYSTR("maxThreadsDim"), maxThreadsDim); 1964 | 1965 | PyObject *maxGridSize = PyList_New(3); 1966 | PyList_SET_ITEM(maxGridSize, 0, PYUINT(dev->maxGridSize[0])); 1967 | PyList_SET_ITEM(maxGridSize, 1, PYUINT(dev->maxGridSize[1])); 1968 | PyList_SET_ITEM(maxGridSize, 2, PYUINT(dev->maxGridSize[2])); 1969 | PyDict_SetItem(d, PYSTR("maxGridSize"), maxGridSize); 1970 | 1971 | PyList_SET_ITEM(l, (Py_ssize_t)i, d); 1972 | } 1973 | return l; 1974 | } 1975 | Py_RETURN_NONE; 1976 | } 1977 | 1978 | /* 1979 | ################################################################################ 1980 | # Nvmon Marker API related functions 1981 | ################################################################################ 1982 | */ 1983 | 1984 | static PyObject * 1985 | likwid_gpumarkerinit(PyObject *self, PyObject *args) 1986 | { 1987 | likwid_gpuMarkerInit(); 1988 | Py_RETURN_NONE; 1989 | } 1990 | 1991 | 1992 | static PyObject * 1993 | likwid_gpumarkerregisterregion(PyObject *self, PyObject *args) 1994 | { 1995 | const char *regiontag; 1996 | int ret; 1997 | if (!PyArg_ParseTuple(args, "s", ®iontag)) 1998 | return NULL; 1999 | 2000 | ret = likwid_gpuMarkerRegisterRegion(regiontag); 2001 | return Py_BuildValue("i", ret); 2002 | } 2003 | 2004 | static PyObject * 2005 | likwid_gpumarkerstartregion(PyObject *self, PyObject *args) 2006 | { 2007 | const char *regiontag; 2008 | int ret; 2009 | if (!PyArg_ParseTuple(args, "s", ®iontag)) 2010 | return NULL; 2011 | 2012 | ret = likwid_gpuMarkerStartRegion(regiontag); 2013 | return Py_BuildValue("i", ret); 2014 | } 2015 | 2016 | static PyObject * 2017 | likwid_gpumarkerstopregion(PyObject *self, PyObject *args) 2018 | { 2019 | const char *regiontag; 2020 | int ret; 2021 | if (!PyArg_ParseTuple(args, "s", ®iontag)) 2022 | return NULL; 2023 | 2024 | ret = likwid_gpuMarkerStopRegion(regiontag); 2025 | return Py_BuildValue("i", ret); 2026 | } 2027 | 2028 | static PyObject * 2029 | likwid_gpumarkergetregion(PyObject *self, PyObject *args) 2030 | { 2031 | int i; 2032 | int currentGroup = 0; 2033 | const char *regiontag = NULL; 2034 | int nr_events = 0; 2035 | double* events = NULL; 2036 | double time = 0; 2037 | int count = 0; 2038 | int nr_gpus = 0; 2039 | Py_ssize_t pyLen = 0; 2040 | PyObject *pyList; 2041 | if (!PyArg_ParseTuple(args, "s", ®iontag)) 2042 | return NULL; 2043 | currentGroup = nvmon_getIdOfActiveGroup(); 2044 | nr_events = nvmon_getNumberOfEvents(currentGroup); 2045 | events = (double*) malloc(nr_events * sizeof(double)); 2046 | if (events == NULL) 2047 | { 2048 | return NULL; 2049 | } 2050 | for (i = 0; i < nr_events; i++) 2051 | { 2052 | events[i] = 0.0; 2053 | } 2054 | pyLen = (Py_ssize_t)nr_events; 2055 | pyList = PyList_New(pyLen); 2056 | likwid_gpuMarkerGetRegion(regiontag, &nr_gpus, &nr_events, events, &time, &count); 2057 | for (i=0; i< nr_events; i++) 2058 | { 2059 | PyList_SET_ITEM(pyList, (Py_ssize_t)i, Py_BuildValue("d", events[i])); 2060 | } 2061 | free(events); 2062 | return Py_BuildValue("iiOdi", nr_gpus, nr_events, pyList, time, count); 2063 | } 2064 | 2065 | static PyObject * 2066 | likwid_gpumarkernextgroup(PyObject *self, PyObject *args) 2067 | { 2068 | likwid_gpuMarkerNextGroup(); 2069 | Py_RETURN_NONE; 2070 | } 2071 | 2072 | static PyObject * 2073 | likwid_gpumarkerresetregion(PyObject *self, PyObject *args) 2074 | { 2075 | const char *regiontag; 2076 | int ret; 2077 | if (!PyArg_ParseTuple(args, "s", ®iontag)) 2078 | return NULL; 2079 | 2080 | ret = likwid_gpuMarkerResetRegion(regiontag); 2081 | return Py_BuildValue("i", ret); 2082 | } 2083 | 2084 | 2085 | static PyObject * 2086 | likwid_gpumarkerclose(PyObject *self, PyObject *args) 2087 | { 2088 | likwid_gpuMarkerClose(); 2089 | Py_RETURN_NONE; 2090 | } 2091 | 2092 | 2093 | /* 2094 | ################################################################################ 2095 | # Nvmon related functions 2096 | ################################################################################ 2097 | */ 2098 | 2099 | static PyObject * 2100 | likwid_nvmon_init(PyObject *self, PyObject *args) 2101 | { 2102 | int ret, i; 2103 | int nrGpus = 0; 2104 | PyObject * pyList; 2105 | 2106 | if (gpuTopology_initialized == 0) 2107 | { 2108 | gputopology_init(); 2109 | gpuTopology_initialized = 1; 2110 | gputopo = get_gpuTopology(); 2111 | } 2112 | if ((gpuTopology_initialized) && (gputopo == NULL)) 2113 | { 2114 | gputopo = get_gpuTopology(); 2115 | } 2116 | 2117 | PyArg_ParseTuple(args, "O!", &PyList_Type, &pyList); 2118 | if (pyList == NULL) 2119 | { 2120 | printf("No function argument\n"); 2121 | return PYINT(1); 2122 | } 2123 | if (!PyList_Check(pyList)) 2124 | { 2125 | printf("Function argument is no list\n"); 2126 | return PYINT(1); 2127 | } 2128 | nrGpus = PyList_Size(pyList); 2129 | int * gpulist = malloc(nrGpus * sizeof(int)); 2130 | if (!gpulist) 2131 | { 2132 | printf("Cannot allocate space for gpu list\n"); 2133 | return PYINT(1); 2134 | } 2135 | for (i=0; i= nvmon_getNumberOfGroups()) 2234 | { 2235 | newgroup = 0; 2236 | } 2237 | if (newgroup == nvmon_getIdOfActiveGroup()) 2238 | { 2239 | return PYINT(-1); 2240 | } 2241 | ret = nvmon_switchActiveGroup(newgroup); 2242 | return PYINT(ret); 2243 | } 2244 | 2245 | static PyObject * 2246 | likwid_nvmon_finalize(PyObject *self, PyObject *args) 2247 | { 2248 | if (nvmon_initialized == 1) 2249 | { 2250 | nvmon_finalize(); 2251 | nvmon_initialized = 0; 2252 | } 2253 | if (gpuTopology_initialized == 1) 2254 | { 2255 | topology_gpu_finalize(); 2256 | gpuTopology_initialized = 0; 2257 | gputopo = NULL; 2258 | } 2259 | return PYINT(0); 2260 | } 2261 | 2262 | static PyObject * 2263 | likwid_nvmon_getResult(PyObject *self, PyObject *args) 2264 | { 2265 | int g, e, t; 2266 | double result; 2267 | PyArg_ParseTuple(args, "iii", &g, &e, &t); 2268 | result = nvmon_getResult(g, e, t); 2269 | return Py_BuildValue("d", result); 2270 | } 2271 | 2272 | static PyObject * 2273 | likwid_nvmon_getLastResult(PyObject *self, PyObject *args) 2274 | { 2275 | int g, e, t; 2276 | double result; 2277 | PyArg_ParseTuple(args, "iii", &g, &e, &t); 2278 | result = nvmon_getLastResult(g, e, t); 2279 | return Py_BuildValue("d", result); 2280 | } 2281 | 2282 | static PyObject * 2283 | likwid_nvmon_getMetric(PyObject *self, PyObject *args) 2284 | { 2285 | int g, m, t; 2286 | double result; 2287 | PyArg_ParseTuple(args, "iii", &g, &m, &t); 2288 | result = nvmon_getMetric(g, m, t); 2289 | return Py_BuildValue("d", result); 2290 | } 2291 | 2292 | static PyObject * 2293 | likwid_nvmon_getLastMetric(PyObject *self, PyObject *args) 2294 | { 2295 | int g, m, t; 2296 | double result = 0.0; 2297 | PyArg_ParseTuple(args, "iii", &g, &m, &t); 2298 | result = nvmon_getLastMetric(g, m, t); 2299 | return Py_BuildValue("d", result); 2300 | } 2301 | 2302 | static PyObject * 2303 | likwid_nvmon_getNumberOfGroups(PyObject *self, PyObject *args) 2304 | { 2305 | if (nvmon_initialized == 0) 2306 | { 2307 | return 0; 2308 | } 2309 | return PYINT(nvmon_getNumberOfGroups()); 2310 | } 2311 | 2312 | static PyObject * 2313 | likwid_nvmon_getIdOfActiveGroup(PyObject *self, PyObject *args) 2314 | { 2315 | if (nvmon_initialized == 0) 2316 | { 2317 | return 0; 2318 | } 2319 | return PYINT(nvmon_getIdOfActiveGroup()); 2320 | } 2321 | 2322 | static PyObject * 2323 | likwid_nvmon_getNumberOfGpus(PyObject *self, PyObject *args) 2324 | { 2325 | if (nvmon_initialized == 0) 2326 | { 2327 | return 0; 2328 | } 2329 | return PYINT(nvmon_getNumberOfGPUs()); 2330 | } 2331 | 2332 | static PyObject * 2333 | likwid_nvmon_getTimeOfGroup(PyObject *self, PyObject *args) 2334 | { 2335 | if (nvmon_initialized == 0) 2336 | { 2337 | return 0; 2338 | } 2339 | int groupId; 2340 | PyArg_ParseTuple(args, "i", &groupId); 2341 | return Py_BuildValue("d", nvmon_getTimeOfGroup(groupId)); 2342 | } 2343 | 2344 | static PyObject * 2345 | likwid_nvmon_getNumberOfEvents(PyObject *self, PyObject *args) 2346 | { 2347 | if (nvmon_initialized == 0) 2348 | { 2349 | return 0; 2350 | } 2351 | int groupId; 2352 | PyArg_ParseTuple(args, "i", &groupId); 2353 | return PYINT(nvmon_getNumberOfEvents(groupId)); 2354 | } 2355 | 2356 | static PyObject * 2357 | likwid_nvmon_getNumberOfMetrics(PyObject *self, PyObject *args) 2358 | { 2359 | if (nvmon_initialized == 0) 2360 | { 2361 | return 0; 2362 | } 2363 | int groupId; 2364 | PyArg_ParseTuple(args, "i", &groupId); 2365 | return PYINT(nvmon_getNumberOfMetrics(groupId)); 2366 | } 2367 | 2368 | static PyObject * 2369 | likwid_nvmon_getNameOfEvent(PyObject *self, PyObject *args) 2370 | { 2371 | if (nvmon_initialized == 0) 2372 | { 2373 | return 0; 2374 | } 2375 | int g, e; 2376 | PyArg_ParseTuple(args, "ii", &g, &e); 2377 | return PYSTR(nvmon_getEventName(g,e)); 2378 | } 2379 | 2380 | static PyObject * 2381 | likwid_nvmon_getNameOfCounter(PyObject *self, PyObject *args) 2382 | { 2383 | if (nvmon_initialized == 0) 2384 | { 2385 | return 0; 2386 | } 2387 | int g, c; 2388 | PyArg_ParseTuple(args, "ii", &g, &c); 2389 | return PYSTR(nvmon_getCounterName(g,c)); 2390 | } 2391 | 2392 | static PyObject * 2393 | likwid_nvmon_getNameOfMetric(PyObject *self, PyObject *args) 2394 | { 2395 | if (nvmon_initialized == 0) 2396 | { 2397 | return 0; 2398 | } 2399 | int g, m; 2400 | PyArg_ParseTuple(args, "ii", &g, &m); 2401 | return PYSTR(nvmon_getMetricName(g,m)); 2402 | } 2403 | 2404 | static PyObject * 2405 | likwid_nvmon_getNameOfGroup(PyObject *self, PyObject *args) 2406 | { 2407 | if (nvmon_initialized == 0) 2408 | { 2409 | return 0; 2410 | } 2411 | int groupId; 2412 | PyArg_ParseTuple(args, "i", &groupId); 2413 | return PYSTR(nvmon_getGroupName(groupId)); 2414 | } 2415 | 2416 | static PyObject * 2417 | likwid_nvmon_getShortInfoOfGroup(PyObject *self, PyObject *args) 2418 | { 2419 | if (nvmon_initialized == 0) 2420 | { 2421 | return 0; 2422 | } 2423 | int groupId; 2424 | PyArg_ParseTuple(args, "i", &groupId); 2425 | return PYSTR(nvmon_getGroupInfoShort(groupId)); 2426 | } 2427 | 2428 | static PyObject * 2429 | likwid_nvmon_getLongInfoOfGroup(PyObject *self, PyObject *args) 2430 | { 2431 | if (nvmon_initialized == 0) 2432 | { 2433 | return 0; 2434 | } 2435 | int groupId; 2436 | PyArg_ParseTuple(args, "i", &groupId); 2437 | return PYSTR(nvmon_getGroupInfoLong(groupId)); 2438 | } 2439 | 2440 | static PyObject * 2441 | likwid_nvmon_getGroups(PyObject *self, PyObject *args) 2442 | { 2443 | int i, ret; 2444 | char** tmp, **infos, **longs; 2445 | PyObject *l; 2446 | if (gpuTopology_initialized == 0) 2447 | { 2448 | topology_gpu_init(); 2449 | gpuTopology_initialized = 1; 2450 | } 2451 | if (gpuTopology_initialized && gputopo == NULL) 2452 | { 2453 | gputopo = get_gpuTopology(); 2454 | } 2455 | ret = nvmon_getGroups(&tmp, &infos, &longs); 2456 | if (ret > 0) 2457 | { 2458 | l = PyList_New(ret); 2459 | for(i=0;i= DEBUGLEV_ONLY_ERROR && verbosity <= DEBUGLEV_DEVELOP) 2483 | { 2484 | nvmon_setVerbosity(verbosity); 2485 | return Py_BuildValue("i", verbosity); 2486 | } 2487 | return Py_BuildValue("i", -1); 2488 | } 2489 | 2490 | static PyObject * 2491 | likwid_nvmon_getEventsOfGpu(PyObject *self, PyObject *args) 2492 | { 2493 | int g; 2494 | if (!PyArg_ParseTuple(args, "i", &g)) 2495 | Py_RETURN_NONE; 2496 | if (gpuTopology_initialized == 0) 2497 | { 2498 | topology_gpu_init(); 2499 | gpuTopology_initialized = 1; 2500 | } 2501 | if (gpuTopology_initialized && gputopo == NULL) 2502 | { 2503 | gputopo = get_gpuTopology(); 2504 | } 2505 | if (g < 0 || g >= gputopo->numDevices) 2506 | Py_RETURN_NONE; 2507 | NvmonEventList_t l = NULL; 2508 | 2509 | int num_events = nvmon_getEventsOfGpu(g, &l); 2510 | if (num_events > 0) 2511 | { 2512 | PyObject *o = PyList_New(l->numEvents); 2513 | 2514 | for (int i = 0; i < l->numEvents; i++) 2515 | { 2516 | PyObject *d = PyDict_New(); 2517 | PyDict_SetItem(d, PYSTR("name"), PYSTR(l->events[i].name)); 2518 | PyDict_SetItem(d, PYSTR("desc"), PYSTR(l->events[i].desc)); 2519 | PyDict_SetItem(d, PYSTR("limit"), PYSTR(l->events[i].limit)); 2520 | PyList_SET_ITEM(o, (Py_ssize_t)i, d); 2521 | } 2522 | nvmon_returnEventsOfGpu(l); 2523 | return o; 2524 | } 2525 | Py_RETURN_NONE; 2526 | } 2527 | 2528 | #endif 2529 | 2530 | static PyMethodDef LikwidMethods[] = { 2531 | {"likwidversion", likwid_lversion, METH_VARARGS, "Get the likwid version numbers."}, 2532 | {"markerinit", likwid_markerinit, METH_VARARGS, "Initialize the LIKWID Marker API."}, 2533 | {"markerthreadinit", likwid_markerthreadinit, METH_VARARGS, "Initialize threads for the LIKWID Marker API."}, 2534 | {"markerregisterregion", likwid_markerregisterregion, METH_VARARGS, "Register a region to the LIKWID Marker API. Optional"}, 2535 | {"markerstartregion", likwid_markerstartregion, METH_VARARGS, "Start a code region."}, 2536 | {"markerstopregion", likwid_markerstopregion, METH_VARARGS, "Stop a code region."}, 2537 | {"markergetregion", likwid_markergetregion, METH_VARARGS, "Get the current results for a code region."}, 2538 | {"markernextgroup", likwid_markernextgroup, METH_VARARGS, "Switch to next event set."}, 2539 | {"markerclose", likwid_markerclose, METH_VARARGS, "Close the Marker API and write results to file."}, 2540 | {"markerreset", likwid_markerresetregion, METH_VARARGS, "Reset the values of the code region to 0"}, 2541 | {"getprocessorid", likwid_getprocessorid, METH_VARARGS, "Returns the current CPU ID."}, 2542 | {"pinprocess", likwid_pinprocess, METH_VARARGS, "Pins the current process to the given CPU."}, 2543 | {"pinthread", likwid_pinthread, METH_VARARGS, "Pins the current thread to the given CPU."}, 2544 | /* misc functions */ 2545 | {"setverbosity", likwid_setverbosity, METH_VARARGS, "Set the verbosity for the LIKWID library."}, 2546 | /* configuration functions */ 2547 | {"initconfiguration", likwid_initconfiguration, METH_VARARGS, "Initialize the configuration module."}, 2548 | {"destroyconfiguration", likwid_destroyconfiguration, METH_VARARGS, "Finalize the configuration module."}, 2549 | {"setgrouppath", likwid_setgrouppath, METH_VARARGS, "Set search path for performance group files"}, 2550 | {"getconfiguration", likwid_getconfiguration, METH_VARARGS, "Get the configration information."}, 2551 | /* access functions */ 2552 | {"hpmmode", likwid_hpmmode, METH_VARARGS, "Set the access mode for the HPM access module."}, 2553 | {"hpminit", likwid_hpminit, METH_VARARGS, "Initialize the HPM access module."}, 2554 | {"hpmaddthread", likwid_hpmaddthread, METH_VARARGS, "Add the current thread/CPU to the access module."}, 2555 | {"hpmfinalize", likwid_hpmfinalize, METH_VARARGS, "Finalize the HPM access module."}, 2556 | /* topology functions */ 2557 | {"inittopology", likwid_inittopology, METH_VARARGS, "Initialize the topology module."}, 2558 | {"finalizetopology", likwid_finalizetopology, METH_VARARGS, "Finalize the topology module."}, 2559 | {"getcputopology", likwid_getcputopology, METH_VARARGS, "Get the topology information for the current system."}, 2560 | {"getcpuinfo", likwid_getcpuinfo, METH_VARARGS, "Get the system information for the current system."}, 2561 | {"printsupportedcpus", likwid_printsupportedcpus, METH_VARARGS, "Print all CPU variants supported by current version of LIKWID."}, 2562 | /* numa functions */ 2563 | {"initnuma", likwid_initnuma, METH_VARARGS, "Initialize the NUMA module."}, 2564 | {"finalizenuma", likwid_finalizenuma, METH_VARARGS, "Finalize the NUMA module."}, 2565 | /* affinity functions */ 2566 | {"initaffinity", likwid_initaffinity, METH_VARARGS, "Initialize the affinity module."}, 2567 | {"finalizeaffinity", likwid_finalizeaffinity, METH_VARARGS, "Finalize the affinity module."}, 2568 | {"cpustr_to_cpulist", likwid_cpustr_to_cpulist, METH_VARARGS, "Translate cpu string to list of cpus."}, 2569 | /* timing functions */ 2570 | {"getcpuclock", likwid_getCpuClock, METH_VARARGS, "Return the clock frequency of the current system."}, 2571 | {"startclock", likwid_startClock, METH_VARARGS, "Start a time measurement."}, 2572 | {"stopclock", likwid_stopClock, METH_VARARGS, "Stop a time measurement."}, 2573 | {"getclockcycles", likwid_getClockCycles, METH_VARARGS, "Return the clock ticks between start and stop."}, 2574 | {"getclock", likwid_getClock, METH_VARARGS, "Return the time in seconds between start and stop."}, 2575 | /* temperature functions */ 2576 | {"inittemp", likwid_initTemp, METH_VARARGS, "Initialize temperature module of LIKWID."}, 2577 | {"readtemp", likwid_readTemp, METH_VARARGS, "Read current temperature."}, 2578 | /* power functions */ 2579 | {"getpowerinfo", likwid_getPowerInfo, METH_VARARGS, "Initialize and get power information."}, 2580 | {"putpowerinfo", likwid_putPowerInfo, METH_VARARGS, "Finalize and return power information."}, 2581 | {"startpower", likwid_startPower, METH_VARARGS, "Start a power measurement."}, 2582 | {"stoppower", likwid_stopPower, METH_VARARGS, "Stop a power measurement."}, 2583 | {"getpower", likwid_getPower, METH_VARARGS, "Get the energy information from a power measurement."}, 2584 | /* perfmon functions */ 2585 | {"init", likwid_init, METH_VARARGS, "Initialize the whole Likwid system including Performance Monitoring module."}, 2586 | {"addeventset", likwid_addEventSet, METH_VARARGS, "Add an event set to LIKWID."}, 2587 | {"setup", likwid_setupCounters, METH_VARARGS, "Setup measuring an event set with LIKWID."}, 2588 | {"start", likwid_startCounters, METH_VARARGS, "Start measuring an event set with LIKWID."}, 2589 | {"stop", likwid_stopCounters, METH_VARARGS, "Stop measuring an event set with LIKWID."}, 2590 | {"read", likwid_readCounters, METH_VARARGS, "Read the current values of the configured event set with LIKWID."}, 2591 | {"readcpu", likwid_readCountersCpu, METH_VARARGS, "Read the current values of the configured event set on a CPU"}, 2592 | {"readgroup", likwid_readGroupCounters, METH_VARARGS, "Read the current values of the given group ID on all CPUs"}, 2593 | {"readgroupthread", likwid_readGroupThreadCounters, METH_VARARGS, "Read the current values of the given group ID of the given thread"}, 2594 | {"switch", likwid_switchGroup, METH_VARARGS, "Switch the currently set up group."}, 2595 | {"finalize", likwid_finalize, METH_VARARGS, "Finalize the whole Likwid system including Performance Monitoring module."}, 2596 | {"getresult", likwid_getResult, METH_VARARGS, "Get the current result of a measurement."}, 2597 | {"getlastresult", likwid_getLastResult, METH_VARARGS, "Get the result of the last measurement cycle."}, 2598 | {"getmetric", likwid_getMetric, METH_VARARGS, "Get the current result of a derived metric."}, 2599 | {"getlastmetric", likwid_getLastMetric, METH_VARARGS, "Get the current result of a derived metric with values from the last measurement cycle."}, 2600 | {"getnumberofgroups", likwid_getNumberOfGroups, METH_VARARGS, "Get the amount of currently configured groups."}, 2601 | {"getnumberofevents", likwid_getNumberOfEvents, METH_VARARGS, "Get the amount of events in a groups."}, 2602 | {"getnumberofmetrics", likwid_getNumberOfMetrics, METH_VARARGS, "Get the amount of events in a groups."}, 2603 | {"getnumberofthreads", likwid_getNumberOfThreads, METH_VARARGS, "Get the amount of configured threads."}, 2604 | {"getidofactivegroup", likwid_getIdOfActiveGroup, METH_VARARGS, "Get the ID of currently active group."}, 2605 | {"gettimeofgroup", likwid_getTimeOfGroup, METH_VARARGS, "Get the runtime of a group."}, 2606 | {"getgroups", likwid_getGroups, METH_VARARGS, "Get a list of all available performance groups."}, 2607 | {"getnameofevent", likwid_getNameOfEvent, METH_VARARGS, "Return the name of an event in a group."}, 2608 | {"getnameofcounter", likwid_getNameOfCounter, METH_VARARGS, "Return the name of a counter in a group."}, 2609 | {"getnameofmetric", likwid_getNameOfMetric, METH_VARARGS, "Return the name of a metric in a group."}, 2610 | {"getnameofgroup", likwid_getNameOfGroup, METH_VARARGS, "Return the name of a group."}, 2611 | {"getshortinfoofgroup", likwid_getShortInfoOfGroup, METH_VARARGS, "Return the short description of a group."}, 2612 | {"getlonginfoofgroup", likwid_getLongInfoOfGroup, METH_VARARGS, "Return the long description of a group."}, 2613 | /* perfmon markerAPI functions */ 2614 | {"markerreadfile", likwid_readMarkerFile, METH_VARARGS, "Read in the results from a Marker API run."}, 2615 | {"markernumregions", likwid_markerNumRegions, METH_VARARGS, "Return the number of regions from a Marker API run."}, 2616 | {"markerregiongroup", likwid_markerRegionGroup, METH_VARARGS, "Return the group of a region from a Marker API run."}, 2617 | {"markerregionevents", likwid_markerRegionEvents, METH_VARARGS, "Return the number of events of a region from a Marker API run."}, 2618 | {"markerregiontag", likwid_markerRegionTag, METH_VARARGS, "Return the tag of a region from a Marker API run."}, 2619 | {"markerregionthreads", likwid_markerRegionThreads, METH_VARARGS, "Return the number of threads of a region from a Marker API run."}, 2620 | {"markerregioncpulist", likwid_markerRegionCpulist, METH_VARARGS, "Returns the list of CPUs that took part in the region."}, 2621 | {"markerregiontime", likwid_markerRegionTime, METH_VARARGS, "Return the runtime of a region for a thread from a Marker API run."}, 2622 | {"markerregioncount", likwid_markerRegionCount, METH_VARARGS, "Return the call count of a region for a thread from a Marker API run."}, 2623 | {"markerregionresult", likwid_markerRegionResult, METH_VARARGS, "Return the result of a region for a event/thread combination from a Marker API run."}, 2624 | {"markerregionmetric", likwid_markerRegionMetric, METH_VARARGS, "Return the metric value of a region for a metric/thread combination from a Marker API run."}, 2625 | /* CPU frequency functions */ 2626 | {"getcpuclockcurrent", likwid_freqGetCpuClockCurrent, METH_VARARGS, "Returns the current CPU frequency (in Hz) of the given CPU."}, 2627 | {"getcpuclockmax", likwid_freqGetCpuClockMax, METH_VARARGS, "Returns the maximal CPU frequency (in Hz) of the given CPU."}, 2628 | {"getcpuclockmin", likwid_freqGetCpuClockMin, METH_VARARGS, "Returns the minimal CPU frequency (in Hz) of the given CPU."}, 2629 | 2630 | {"setcpuclockmax", likwid_freqSetCpuClockMax, METH_VARARGS, "Sets the maximal CPU frequency (in Hz) of the given CPU."}, 2631 | {"setcpuclockmin", likwid_freqSetCpuClockMin, METH_VARARGS, "Sets the minimal CPU frequency (in Hz) of the given CPU."}, 2632 | {"getgovernor", likwid_freqGetGovernor, METH_VARARGS, "Returns the CPU frequency govneror of the given CPU."}, 2633 | {"setgovernor", likwid_freqSetGovernor, METH_VARARGS, "Sets the CPU frequency govneror of the given CPU."}, 2634 | {"getavailfreqs", likwid_freqGetAvailFreq, METH_VARARGS, "Returns the available CPU frequency steps (in GHz, returns string)."}, 2635 | {"getavailgovs", likwid_freqGetAvailGovs, METH_VARARGS, "Returns the available CPU frequency governors (returns string)."}, 2636 | #if 0 2637 | {"getuncoreclockcurrent", likwid_freqGetUncoreClockCurrent, METH_VARARGS, "Returns the current Uncore frequency of the given CPU socket."}, 2638 | #endif 2639 | {"getuncoreclockmax", likwid_freqGetUncoreClockMax, METH_VARARGS, "Returns the maximal Uncore frequency (in Hz) of the given CPU socket."}, 2640 | {"getuncoreclockmin", likwid_freqGetUncoreClockMin, METH_VARARGS, "Returns the minimal Uncore frequency (in Hz) of the given CPU socket."}, 2641 | {"setuncoreclockmax", likwid_freqSetUncoreClockMax, METH_VARARGS, "Sets the maximal Uncore frequency (in Hz) of the given CPU socket."}, 2642 | {"setuncoreclockmin", likwid_freqSetUncoreClockMin, METH_VARARGS, "Sets the minimal Uncore frequency (in Hz) of the given CPU socket."}, 2643 | #if (LIKWID_MAJOR == 5) 2644 | /* CPU frequency functions (additions for LIKWID 5) */ 2645 | {"freqinit", likwid_freqInit, METH_VARARGS, "Initializes the frequency module"}, 2646 | {"freqfinalize", likwid_freqFinalize, METH_VARARGS, "Finalizes the frequency module"}, 2647 | {"getconfcpuclockmax", likwid_freqGetConfCpuClockMax, METH_VARARGS, "Returns the maximal configurable CPU frequency (in Hz) of the given CPU."}, 2648 | {"getconfcpuclockmin", likwid_freqGetConfCpuClockMin, METH_VARARGS, "Returns the minimal configurable CPU frequency (in Hz) of the given CPU."}, 2649 | /* GPU functions */ 2650 | #ifdef LIKWID_NVMON 2651 | {"gpustr_to_gpulist", likwid_gpustr_to_gpulist, METH_VARARGS, "Translate gpu string to list of gpus."}, 2652 | {"initgputopology", likwid_initgputopology, METH_VARARGS, "Initialize the topology module for NVIDIA GPUs."}, 2653 | {"finalizegputopology", likwid_finalizegputopology, METH_VARARGS, "Finalize the topology module for NVIDIA GPUs."}, 2654 | {"getgputopology", likwid_getgputopology, METH_VARARGS, "Get the topology information for the current system for NVIDIA GPUs."}, 2655 | /* Nvmon Marker API functions */ 2656 | {"gpumarkerinit", likwid_gpumarkerinit, METH_VARARGS, "Initialize the LIKWID Nvmon Marker API."}, 2657 | {"gpumarkerregisterregion", likwid_gpumarkerregisterregion, METH_VARARGS, "Register a region to the LIKWID Nvmon Marker API. Optional"}, 2658 | {"gpumarkerstartregion", likwid_gpumarkerstartregion, METH_VARARGS, "Start a Nvmon code region."}, 2659 | {"gpumarkerstopregion", likwid_gpumarkerstopregion, METH_VARARGS, "Stop a Nvmon code region."}, 2660 | {"gpumarkergetregion", likwid_gpumarkergetregion, METH_VARARGS, "Get the current results for a Nvmon code region."}, 2661 | {"gpumarkernextgroup", likwid_gpumarkernextgroup, METH_VARARGS, "Switch to next Nvmon event set."}, 2662 | {"gpumarkerclose", likwid_gpumarkerclose, METH_VARARGS, "Close the Nvmon Marker API and write results to file."}, 2663 | {"gpumarkerreset", likwid_gpumarkerresetregion, METH_VARARGS, "Reset the values of the Nvmon code region to 0"}, 2664 | /* Nvmon functions */ 2665 | {"nvinit", likwid_nvmon_init, METH_VARARGS, "Initialize the whole Likwid Nvmon system including Nvmon Performance Monitoring module."}, 2666 | {"nvaddeventset", likwid_nvmon_addEventSet, METH_VARARGS, "Add an Nvmon event set to LIKWID."}, 2667 | {"nvsetup", likwid_nvmon_setupCounters, METH_VARARGS, "Setup measuring an Nvmon event set with LIKWID."}, 2668 | {"nvstart", likwid_nvmon_startCounters, METH_VARARGS, "Start measuring an Nvmon event set with LIKWID."}, 2669 | {"nvstop", likwid_nvmon_stopCounters, METH_VARARGS, "Stop measuring an Nvmon event set with LIKWID."}, 2670 | {"nvread", likwid_nvmon_readCounters, METH_VARARGS, "Read the current values of the configured Nvmon event set with LIKWID."}, 2671 | {"nvswitch", likwid_nvmon_switchGroup, METH_VARARGS, "Switch the currently set up Nvmon group."}, 2672 | {"nvfinalize", likwid_nvmon_finalize, METH_VARARGS, "Finalize the whole Likwid Nvmon system including Nvmon Performance Monitoring module."}, 2673 | {"nvgetresult", likwid_nvmon_getResult, METH_VARARGS, "Get the current Nvmon result of a measurement."}, 2674 | {"nvgetlastresult", likwid_nvmon_getLastResult, METH_VARARGS, "Get the Nvmon result of the last measurement cycle."}, 2675 | {"nvgetmetric", likwid_nvmon_getMetric, METH_VARARGS, "Get the current Nvmon result of a derived metric."}, 2676 | {"nvgetlastmetric", likwid_nvmon_getLastMetric, METH_VARARGS, "Get the current Nvmon result of a derived metric with values from the last measurement cycle."}, 2677 | {"nvgetnumberofgroups", likwid_nvmon_getNumberOfGroups, METH_VARARGS, "Get the amount of currently configured Nvmon groups."}, 2678 | {"nvgetnumberofevents", likwid_nvmon_getNumberOfEvents, METH_VARARGS, "Get the amount of events in a Nvmon groups."}, 2679 | {"nvgetnumberofmetrics", likwid_nvmon_getNumberOfMetrics, METH_VARARGS, "Get the amount of events in a Nvmon groups."}, 2680 | {"nvgetnumberofgpus", likwid_nvmon_getNumberOfGpus, METH_VARARGS, "Get the amount of configured GPUs."}, 2681 | {"nvgetidofactivegroup", likwid_nvmon_getIdOfActiveGroup, METH_VARARGS, "Get the ID of currently active Nvmon group."}, 2682 | {"nvgettimeofgroup", likwid_nvmon_getTimeOfGroup, METH_VARARGS, "Get the runtime of a Nvmon group."}, 2683 | {"nvgetgroups", likwid_nvmon_getGroups, METH_VARARGS, "Get a list of all available Nvmon performance groups."}, 2684 | {"nvgetnameofevent", likwid_nvmon_getNameOfEvent, METH_VARARGS, "Return the name of an event in a Nvmon group."}, 2685 | {"nvgetnameofcounter", likwid_nvmon_getNameOfCounter, METH_VARARGS, "Return the name of a counter in a Nvmon group."}, 2686 | {"nvgetnameofmetric", likwid_nvmon_getNameOfMetric, METH_VARARGS, "Return the name of a metric in a Nvmon group."}, 2687 | {"nvgetnameofgroup", likwid_nvmon_getNameOfGroup, METH_VARARGS, "Return the name of a Nvmon group."}, 2688 | {"nvgetshortinfoofgroup", likwid_nvmon_getShortInfoOfGroup, METH_VARARGS, "Return the short description of a Nvmon group."}, 2689 | {"nvgetlonginfoofgroup", likwid_nvmon_getLongInfoOfGroup, METH_VARARGS, "Return the long description of a Nvmon group."}, 2690 | {"nvgeteventsofgpu", likwid_nvmon_getEventsOfGpu, METH_VARARGS, "Get the events of a gpu."} 2691 | /* Misc function */ 2692 | {"nvsetverbosity", likwid_nvmon_setverbosity, METH_VARARGS, "Set the verbosity for the LIKWID Nvmon library."}, 2693 | #endif 2694 | #endif 2695 | {NULL, NULL, 0, NULL} 2696 | }; 2697 | 2698 | #if (PY_MAJOR_VERSION == 2) 2699 | PyMODINIT_FUNC 2700 | initpylikwid(void) 2701 | { 2702 | (void) Py_InitModule("pylikwid", LikwidMethods); 2703 | } 2704 | #endif 2705 | 2706 | #if (PY_MAJOR_VERSION == 3) 2707 | static struct PyModuleDef pylikwidmodule = { 2708 | PyModuleDef_HEAD_INIT, 2709 | .m_name = "pylikwid", /* name of module */ 2710 | .m_doc = NULL, /* module documentation, may be NULL */ 2711 | .m_size = -1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */ 2712 | .m_methods = LikwidMethods, 2713 | }; 2714 | 2715 | PyMODINIT_FUNC 2716 | PyInit_pylikwid(void) 2717 | { 2718 | return PyModule_Create(&pylikwidmodule); 2719 | } 2720 | #endif 2721 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os, os.path, glob, re, sys 2 | from distutils.core import setup, Extension 3 | 4 | 5 | # Utility function to read the README.md file. 6 | # Used for the long_description. It"s nice, because now 1) we have a top level 7 | # README.md file and 2) it"s easier to type in the README.md file than to put a raw 8 | # string in below ... 9 | def read(fname): 10 | return open(os.path.join(os.path.dirname(__file__), fname)).read() 11 | 12 | 13 | ver_regex = re.compile(b"so.(\d+)[.]*(\d*)") 14 | 15 | 16 | def generic_iglob(pattern): 17 | result = None 18 | if sys.version_info.major == 3 and sys.version_info.minor > 4: 19 | result = glob.iglob(pattern, recursive=True) 20 | else: 21 | result = glob.iglob(pattern) 22 | return result 23 | 24 | 25 | def find_file(path_iterator): 26 | path = None 27 | path_to_explore = None 28 | is_searching = True 29 | if path_iterator: 30 | while is_searching: 31 | try: 32 | path_to_explore = next(path_iterator) 33 | if os.path.exists(path_to_explore): 34 | path = path_to_explore 35 | is_searching = False 36 | except StopIteration: 37 | is_searching = False 38 | return path 39 | 40 | 41 | def get_hierarchy(): 42 | print("Searching for LIKWID installation in all folders in $PATH, $LIKWID_PREFIX and /usr/local") 43 | print("If you can use LIKWID on the CLI but it is not found, use LIKWID_PREFIX=$(realpath $(dirname $(which likwid-topology))/..)") 44 | include_path = None 45 | library_path = None 46 | library = None 47 | prefix_path = os.getenv('LIKWID_PREFIX', None) 48 | library_pattern = 'lib*/liblikwid.so*' 49 | if prefix_path is not None: 50 | iterator = generic_iglob(os.path.join(prefix_path, library_pattern)) 51 | library = find_file(iterator) 52 | if library is not None: 53 | library_path = os.path.dirname(library) 54 | if library is None: 55 | paths_iterator = iter(os.environ["PATH"].split(":")) 56 | is_searching = True 57 | while is_searching: 58 | try: 59 | path = next(paths_iterator) 60 | prefix_path = os.path.abspath(os.path.join(path, '..')) 61 | iterator = generic_iglob(os.path.join(prefix_path, library_pattern)) 62 | library = find_file(iterator) 63 | if library is not None: 64 | library_path = os.path.dirname(library) 65 | is_searching = False 66 | except StopIteration: 67 | is_searching = False 68 | if library is None: 69 | prefix_path = '/usr/local' 70 | iterator = generic_iglob(os.path.join(prefix_path, library_pattern)) 71 | library = find_file(iterator) 72 | if library is not None: 73 | library_path = os.path.dirname(library) 74 | 75 | include_path = os.path.join(prefix_path, 'include') 76 | if not os.path.exists(os.path.join(include_path, 'likwid.h')): 77 | iterator = generic_iglob(prefix_path + '**/likwid.h') 78 | include_path = find_file(iterator) 79 | if prefix_path is None or not os.path.exists(prefix_path): 80 | raise Exception('Error the likwid prefix directory was not found') 81 | if library is None or not os.path.exists(library): 82 | raise Exception('Error the likwid library was not found') 83 | if library_path is None or not os.path.exists(library_path): 84 | raise Exception('Error the likwid library directory was not found') 85 | if include_path is None or not os.path.exists(include_path): 86 | raise Exception('Error the likwid include directory was not found') 87 | print("Using LIKWID prefix directory at {!s}".format(prefix_path)) 88 | print("Using LIKWID include directory at {!s}".format(include_path)) 89 | print("Using LIKWID library directory at {!s}".format(library_path)) 90 | print("Using LIKWID library named {!s}".format(library)) 91 | m = re.match("lib(.*)\.so", os.path.basename(library)) 92 | if m: 93 | library = m.group(1) 94 | return prefix_path, library_path, library, include_path 95 | 96 | try: 97 | LIKWID_PREFIX, LIKWID_LIBPATH, LIKWID_LIB, LIKWID_INCPATH = get_hierarchy() 98 | print(LIKWID_PREFIX, LIKWID_LIBPATH, LIKWID_LIB, LIKWID_INCPATH) 99 | except Exception as e: 100 | print(e) 101 | sys.exit(1) 102 | 103 | 104 | def get_extra_compile_args(): 105 | extra_args = [] 106 | likwid_header_path = f"{LIKWID_INCPATH}/likwid.h" 107 | with open(likwid_header_path, mode="r") as f: 108 | for line in f: 109 | if not line.startswith("#define LIKWID_VERSION"): 110 | continue 111 | major, release, minor = line.split()[-1].strip("\"").split(".") 112 | extra_args.extend([ 113 | f"-DLIKWID_MAJOR={major}", 114 | f"-DLIKWID_RELEASE={release}", 115 | f"-DLIKWID_MINOR={minor}", 116 | ]) 117 | break 118 | return extra_args 119 | 120 | 121 | pylikwid = Extension("pylikwid", 122 | include_dirs=[LIKWID_INCPATH], 123 | libraries=[LIKWID_LIB], 124 | library_dirs=[LIKWID_LIBPATH], 125 | extra_compile_args=get_extra_compile_args(), 126 | sources=["pylikwid.c"]) 127 | 128 | setup( 129 | name="pylikwid", 130 | version="0.4.2", 131 | author="Thomas Roehl", 132 | author_email="thomas.roehl@googlemail.com", 133 | description="A Python module to access the function of the LIKWID library", 134 | long_description=read("README.rst"), 135 | license="GPLv2", 136 | keywords="hpc performance benchmark analysis", 137 | url="https://github.com/RRZE-HPC/pylikwid", 138 | classifiers=[ 139 | "Development Status :: 3 - Alpha", 140 | "Intended Audience :: Developers", 141 | "Intended Audience :: Science/Research", 142 | "Topic :: Scientific/Engineering", 143 | "Topic :: Software Development", 144 | "Topic :: Utilities", 145 | "License :: OSI Approved :: GNU General Public License v2 (GPLv2)", 146 | "Programming Language :: Python :: 3", 147 | "Programming Language :: Python :: 3.4", 148 | "Programming Language :: Python :: 3.5", 149 | "Programming Language :: Python :: 3.6", 150 | "Programming Language :: Python :: 2", 151 | "Programming Language :: Python :: 2.7", 152 | ], 153 | package_data={ 154 | "pylikwid": ["pylikwid.c", "README.rst", "LICENSE"], 155 | "tests": ["tests/*.py"] 156 | }, 157 | ext_modules=[pylikwid] 158 | ) 159 | -------------------------------------------------------------------------------- /tests/monitoring.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os, sys, re, time, math 4 | 5 | try: 6 | import pylikwid 7 | except ImportError: 8 | print("Cannot load LIKWID python module") 9 | sys.exit(1) 10 | 11 | groups = ["L3"] 12 | sleeptime = 1 13 | if len(groups) == 0: 14 | print("You have to add a performance group name to 'groups' list") 15 | sys.exit(1) 16 | if sleeptime <= 0: 17 | print("Sleep time must be greater than zero") 18 | sys.exit(1) 19 | 20 | 21 | gids = {} 22 | cpus = [] 23 | 24 | ret = pylikwid.hpminit() 25 | if not ret: 26 | print('Failed to initialize access layer for LIKWID') 27 | sys.exit(1) 28 | 29 | 30 | ret = pylikwid.inittopology() 31 | if not ret: 32 | print('Failed to initialize LIKWID topology module') 33 | sys.exit(1) 34 | 35 | 36 | topo = pylikwid.getcputopology() 37 | for t in topo["threadPool"].keys(): 38 | cpus.append(topo["threadPool"][t]["apicId"]) 39 | 40 | 41 | ret = pylikwid.init(cpus) 42 | if ret != 0: 43 | print('Failed to initialize LIKWID perfmon module') 44 | sys.exit(1) 45 | os.environ["LIKWID_FORCE"] = "1" 46 | 47 | if pylikwid.setverbosity(0) != 0: 48 | print('Failed to set verbosity') 49 | sys.exit(1) 50 | 51 | 52 | run = True 53 | try: 54 | while run: 55 | for grp in groups: 56 | if not gids.has_key(grp): 57 | gid = pylikwid.addeventset(grp) 58 | if gid < 0: 59 | print('Failed to add group {} to LIKWID perfmon module'.format(grp)) 60 | groups.remove(grp) 61 | continue 62 | gids[grp] = gid 63 | gid = gids[grp] 64 | timestamp = time.time() 65 | pylikwid.setup(gid) 66 | pylikwid.start() 67 | time.sleep(sleeptime) 68 | pylikwid.stop() 69 | for i in range(len(cpus)): 70 | for m in range(pylikwid.getnumberofmetrics(gid)): 71 | metricname = pylikwid.getnameofmetric(gid, m) 72 | v = float(pylikwid.getlastmetric(gid, m, i)) 73 | if math.isnan(v) or str(v) == "nan": 74 | print("Metric {} on CPU {} failed".format(metricname, cpus[i])) 75 | run = False 76 | elif i == 0: 77 | print("{},cpu={} {} {}".format(metricname, cpus[i], v, timestamp)) 78 | except KeyboardInterrupt: 79 | pass 80 | 81 | pylikwid.finalize() 82 | -------------------------------------------------------------------------------- /tests/testaffinity.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import pylikwid 4 | 5 | def int_join(l, sep): 6 | if l and len(l) > 0: 7 | return sep.join([str(x) for x in l]) 8 | return "\"\"" 9 | 10 | aff = pylikwid.initaffinity() 11 | 12 | for k in aff: 13 | if isinstance(aff[k], int): 14 | print("{}: {}".format(k, aff[k])) 15 | print("") 16 | 17 | for d in aff["domains"]: 18 | print("Domain {}:".format(aff["domains"][d]["tag"])) 19 | print("\t"+int_join(aff["domains"][d]["processorList"], " ")) 20 | print("") 21 | 22 | for sel in ["S0:0-3", "N:3-1", "1,2,3", "E:N:2:1:2"]: 23 | l = pylikwid.cpustr_to_cpulist(sel) 24 | print("CPU string {} results in {}".format(sel, int_join(l, ","))) 25 | 26 | pylikwid.finalizeaffinity() 27 | -------------------------------------------------------------------------------- /tests/testfreq.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import pylikwid 4 | 5 | 6 | pylikwid.inittopology() 7 | topodict = pylikwid.getcputopology() 8 | freqlist = pylikwid.getavailfreqs(0) 9 | govlist = pylikwid.getavailgovs(0) 10 | print("Available frequencies for CPU core 0:\n{}\n".format(freqlist)) 11 | minfreq = float(pylikwid.getcpuclockmin(0)) 12 | maxfreq = float(pylikwid.getcpuclockmax(0)) 13 | print("Available CPU governors for CPU core 0:\n{}\n".format(govlist)) 14 | 15 | 16 | 17 | for idx in topodict["threadPool"]: 18 | cpu = topodict["threadPool"][idx]["apicId"] 19 | print("CPU {} : {} Hz (min: {}, max: {}, gov: {})".format(cpu, pylikwid.getcpuclockcurrent(cpu), 20 | pylikwid.getcpuclockmin(cpu), 21 | pylikwid.getcpuclockmax(cpu), 22 | pylikwid.getgovernor(cpu))) 23 | minunc = int(pylikwid.getuncoreclockmin(0)/1E6) 24 | maxunc = int(pylikwid.getuncoreclockmax(0)/1E6) 25 | print("\nUncore frequencies:") 26 | for socket in range(topodict["numSockets"]): 27 | print("Socket {} : min: {} MHz, max: {} MHz".format(socket, pylikwid.getuncoreclockmin(socket), 28 | pylikwid.getuncoreclockmax(socket))) 29 | 30 | print("\nSet frequency of CPU 1 to minimum {} MHz:".format(int(float(minfreq)/1E6))) 31 | pylikwid.setcpuclockmin(1, int(float(minfreq)/1E3)) 32 | pylikwid.setcpuclockmax(1, int(float(minfreq)/1E3)) 33 | print("CPU {} : {} Hz (min: {}, max: {}, gov: {})".format(1, pylikwid.getcpuclockcurrent(1), 34 | pylikwid.getcpuclockmin(1), 35 | pylikwid.getcpuclockmax(1), 36 | pylikwid.getgovernor(1))) 37 | 38 | print("\nReset frequency of CPU 1:") 39 | pylikwid.setcpuclockmin(1, int(float(minfreq)/1E3)) 40 | pylikwid.setcpuclockmax(1, int(float(maxfreq)/1E3)) 41 | print("CPU {} : {} Hz (min: {}, max: {}, gov: {})".format(1, pylikwid.getcpuclockcurrent(1), 42 | pylikwid.getcpuclockmin(1), 43 | pylikwid.getcpuclockmax(1), 44 | pylikwid.getgovernor(1))) 45 | 46 | gov = pylikwid.getgovernor(1) 47 | oldgov = gov 48 | for g in govlist.split(" "): 49 | if g != gov: 50 | gov = g 51 | break 52 | 53 | print("\nSet governor of CPU 1 to {}:".format(gov)) 54 | pylikwid.setgovernor(1, gov) 55 | print("CPU {} : {} Hz (min: {}, max: {}, gov: {})".format(1, pylikwid.getcpuclockcurrent(1), 56 | pylikwid.getcpuclockmin(1), 57 | pylikwid.getcpuclockmax(1), 58 | pylikwid.getgovernor(1))) 59 | print("\nReset governor of CPU 1 to {}:".format(oldgov)) 60 | pylikwid.setgovernor(1, oldgov) 61 | print("CPU {} : {} Hz (min: {}, max: {}, gov: {})".format(1, pylikwid.getcpuclockcurrent(1), 62 | pylikwid.getcpuclockmin(1), 63 | pylikwid.getcpuclockmax(1), 64 | pylikwid.getgovernor(1))) 65 | 66 | print("\nSet Uncore frequency of socket 0 to minimum {}:".format(minunc)) 67 | pylikwid.setuncoreclockmin(0, minunc) 68 | pylikwid.setuncoreclockmax(0, minunc) 69 | print("Socket {} : min: {} MHz, max: {} MHz".format(0, pylikwid.getuncoreclockmin(0), 70 | pylikwid.getuncoreclockmax(0))) 71 | 72 | print("\nReset Uncore frequency of socket 0:") 73 | pylikwid.setuncoreclockmin(0, minunc) 74 | pylikwid.setuncoreclockmax(0, maxunc) 75 | print("Socket {} : min: {} MHz, max: {} MHz".format(0, pylikwid.getuncoreclockmin(0), 76 | pylikwid.getuncoreclockmax(0))) 77 | 78 | 79 | pylikwid.finalizetopology() 80 | -------------------------------------------------------------------------------- /tests/testlib.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | import pylikwid 5 | 6 | liste = [] 7 | cpus = [0,1] 8 | eventset = "INSTR_RETIRED_ANY:FIXC0" 9 | 10 | err = pylikwid.init(cpus) 11 | if err > 0: 12 | print("Cannot initialize LIKWID") 13 | sys.exit(1) 14 | group = pylikwid.addeventset(eventset) 15 | if group >= 0: 16 | print("Eventset {} added with ID {}".format(eventset, group,)) 17 | else: 18 | print("Failed to add eventset {}".format(eventset)) 19 | sys.exit(1) 20 | err = pylikwid.setup(group) 21 | if err < 0: 22 | print("Setup of group {} failed".format(group)) 23 | sys.exit(1) 24 | err = pylikwid.start() 25 | if err < 0: 26 | print("Start of group {} failed".format(group)) 27 | sys.exit(1) 28 | for i in range(0,1000000): 29 | liste.append(i) 30 | err = pylikwid.stop() 31 | if err < 0: 32 | print("Stop of group {} failed".format(group)) 33 | sys.exit(1) 34 | for thread in range(0,len(cpus)): 35 | print("Result CPU {} : {}".format(cpus[thread], pylikwid.getresult(group,0,thread))) 36 | pylikwid.finalize() 37 | -------------------------------------------------------------------------------- /tests/testmarker.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import pylikwid 4 | 5 | 6 | pylikwid.markerinit() 7 | pylikwid.markerthreadinit() 8 | liste = [] 9 | pylikwid.markerstartregion("liste") 10 | for i in range(0,1000000): 11 | liste.append(i) 12 | 13 | pylikwid.markerstopregion("liste") 14 | nr_events, elist, time, count = pylikwid.markergetregion("liste") 15 | for i, e in enumerate(elist): 16 | print(i, e) 17 | pylikwid.markerclose() 18 | -------------------------------------------------------------------------------- /tests/testpin.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import pylikwid 4 | 5 | def do_work(): 6 | l = [] 7 | for i in range(1000000): 8 | l += [i] 9 | print("Running on CPU {}".format(pylikwid.getprocessorid())) 10 | 11 | 12 | pylikwid.inittopology() 13 | cputopo = pylikwid.getcputopology() 14 | for t in cputopo["threadPool"]: 15 | pylikwid.pinprocess(cputopo["threadPool"][t]["apicId"]) 16 | do_work() 17 | 18 | pylikwid.finalizetopology() 19 | -------------------------------------------------------------------------------- /tests/testtopo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import pylikwid 4 | 5 | pylikwid.inittopology() 6 | infodict = pylikwid.getcpuinfo() 7 | for k in infodict: 8 | print("{}: {}".format(k, infodict[k])) 9 | topodict = pylikwid.getcputopology() 10 | for k in topodict: 11 | if not isinstance(topodict[k], dict): 12 | print("{}: {}".format(k, topodict[k])) 13 | print() 14 | print("CPU topology:") 15 | print("ID\tCore\tThread\tPackage") 16 | for t in topodict["threadPool"]: 17 | print("{}\t{}\t{}\t{}".format(topodict["threadPool"][t]["apicId"], 18 | topodict["threadPool"][t]["coreId"], 19 | topodict["threadPool"][t]["threadId"], 20 | topodict["threadPool"][t]["packageId"])) 21 | 22 | pylikwid.finalizetopology() 23 | --------------------------------------------------------------------------------