├── .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 |
--------------------------------------------------------------------------------