emi
zeus.device.cpu.emi
Windows EMI (Energy Meter Interface) CPU energy monitoring.
-
EMI (Energy Meter Interface): EMI is a Windows interface introduced in Windows 10 that allows applications to read energy consumption data from hardware energy meters. It provides access to RAPL (Running Average Power Limit) counters on Intel processors via a standardized IOCTL interface.
-
Energy Meter Device: An EMI device represents one energy metering unit. On Intel systems, a single EMI device typically exposes multiple channels corresponding to different power domains (e.g., package, DRAM, PP0, PP1) for each CPU socket.
-
Channel: Each EMI device exposes one or more named channels. Channel names follow the pattern
RAPL_Package{N}_{DOMAIN}where N is the socket index and DOMAIN is the power domain (e.g., PKG, DRAM, PP0, PP1).
See: https://learn.microsoft.com/en-us/windows-hardware/drivers/powermeter/energy-meter-interface
ZeusEMINotSupportedError
Bases: ZeusBaseCPUError
Raised when EMI is not available on this system.
Source code in zeus/device/cpu/emi.py
184 185 186 187 188 189 | |
__init__
__init__(message)
Source code in zeus/device/cpu/emi.py
187 188 189 | |
ZeusEMIInitError
Bases: ZeusBaseCPUError
Raised when an EMI device cannot be opened or queried.
Source code in zeus/device/cpu/emi.py
192 193 194 195 196 197 | |
__init__
__init__(message)
Source code in zeus/device/cpu/emi.py
195 196 197 | |
_EMIChannel
Metadata for a single EMI channel.
Source code in zeus/device/cpu/emi.py
346 347 348 349 350 351 352 353 354 | |
EMIFile
Manages an open Windows EMI device handle and reads energy data from it.
Each EMIFile corresponds to one EMI device interface (one device path).
It reads energy values in picowatt-hours and converts them to millijoules.
Attributes:
| Name | Type | Description |
|---|---|---|
path |
str
|
The Windows device interface path. |
version |
int
|
The EMI interface version reported by the device (1 or 2). |
channels |
list[_EMIChannel]
|
Metadata for each channel on this device. |
Source code in zeus/device/cpu/emi.py
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 | |
__init__
__init__(path)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str
|
Windows device interface path (e.g. |
required |
Raises:
| Type | Description |
|---|---|
ZeusEMIInitError
|
If the device cannot be opened or its metadata cannot be read. |
Source code in zeus/device/cpu/emi.py
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 | |
_read_metadata
_read_metadata()
Query the device for its version and channel metadata.
Returns:
| Type | Description |
|---|---|
tuple[int, list[_EMIChannel]]
|
A (version, channels) tuple. |
Raises:
| Type | Description |
|---|---|
ZeusEMIInitError
|
On any IOCTL failure. |
Source code in zeus/device/cpu/emi.py
403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 | |
_parse_channels
staticmethod
_parse_channels(version, raw)
Parse channel metadata from the raw metadata buffer.
EMI_METADATA_V1 layout (offsets in bytes): MeasurementUnit UINT 4 HardwareOEM WCHAR[16] 32 HardwareModel WCHAR[16] 32 HardwareRevision USHORT 2 MeteredHardwareNameSize USHORT 2 MeteredHardwareName WCHAR[] variable
EMI_METADATA_V2 layout (offsets in bytes): HardwareOEM WCHAR[16] 32 @ 0 HardwareModel WCHAR[16] 32 @ 32 HardwareRevision USHORT 2 @ 64 ChannelCount USHORT 2 @ 66 Channels[] @ 68
Each EMI_CHANNEL_V2
MeasurementUnit UINT 4 ChannelNameSize USHORT 2 (bytes, including null terminator) ChannelName WCHAR[] ChannelNameSize bytes
Source code in zeus/device/cpu/emi.py
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 | |
read
read(channel_index)
Read the accumulated energy for the given channel.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
channel_index
|
int
|
Zero-based index of the channel within this device. |
required |
Returns:
| Type | Description |
|---|---|
float
|
The accumulated energy in millijoules. |
Raises:
| Type | Description |
|---|---|
ZeusEMIInitError
|
If the channel is invalid, the channel's measurement unit is not picowatt-hours, or the IOCTL call fails. |
Source code in zeus/device/cpu/emi.py
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 | |
__del__
__del__()
Close the device handle.
During interpreter shutdown module globals may already be cleared, so we
guard against _kernel32/ctypes being None and swallow any
error rather than raising from a finalizer.
Source code in zeus/device/cpu/emi.py
555 556 557 558 559 560 561 562 563 564 565 566 567 568 | |
EMICPU
Bases: CPU
Reads energy for a single Intel CPU package via the Windows EMI interface.
Attributes:
| Name | Type | Description |
|---|---|---|
cpu_index |
int
|
Zero-based package (socket) index. |
Source code in zeus/device/cpu/emi.py
571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 | |
__init__
__init__(cpu_index, emi_file, pkg_channel_index, dram_channel_index)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cpu_index
|
int
|
Zero-based CPU package (socket) index. |
required |
emi_file
|
EMIFile
|
The :class: |
required |
pkg_channel_index
|
int
|
Index of the PKG (package) energy channel in |
required |
dram_channel_index
|
int | None
|
Index of the DRAM energy channel, or |
required |
Source code in zeus/device/cpu/emi.py
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 | |
get_total_energy_consumption
get_total_energy_consumption()
Return the total accumulated energy for this CPU package. Units: mJ.
Source code in zeus/device/cpu/emi.py
598 599 600 601 602 603 604 | |
supports_get_dram_energy_consumption
supports_get_dram_energy_consumption()
Return True if DRAM energy data is available for this package.
Source code in zeus/device/cpu/emi.py
606 607 608 | |
EMICPUs
Bases: CPUs
Manages all Intel CPU packages accessible via the Windows EMI interface.
Each detected RAPL_Package{N}_PKG EMI channel maps to one
:class:EMICPU object at index N.
Source code in zeus/device/cpu/emi.py
611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 | |
cpus
property
cpus
Return the list of :class:EMICPU objects.
__init__
__init__()
Raises:
| Type | Description |
|---|---|
ZeusEMINotSupportedError
|
If EMI is unavailable on this system. |
ZeusEMIInitError
|
If device metadata cannot be queried. |
Source code in zeus/device/cpu/emi.py
618 619 620 621 622 623 624 625 626 627 628 629 630 | |
_init_cpus
_init_cpus()
Build the list of :class:EMICPU objects from all EMI devices.
Source code in zeus/device/cpu/emi.py
632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 | |
__del__
__del__()
Clean up resources.
Source code in zeus/device/cpu/emi.py
698 699 700 | |
_build_emi_guid
_build_emi_guid()
Build the EMI device interface GUID structure.
Source code in zeus/device/cpu/emi.py
200 201 202 203 204 205 206 207 208 | |
_get_emi_device_paths
_get_emi_device_paths()
Enumerate all EMI-compliant device interface paths on this Windows system.
Returns an empty list if no devices are found or if not running on Windows.
Source code in zeus/device/cpu/emi.py
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 | |
_ioctl
_ioctl(handle, code, out_size)
Send a buffered IOCTL with no input buffer and return the output bytes.
Returns None if the call fails.
Source code in zeus/device/cpu/emi.py
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 | |
_find_package_of_processor
_find_package_of_processor(raw, group, number, ptr_size)
Find the index of the processor package containing a logical processor.
Parses the SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX records returned by
GetLogicalProcessorInformationEx with RelationProcessorPackage and
returns the zero-based index of the package whose group affinity contains
the logical processor identified by processor group group and
within-group number number, or None if no package matches.
Record layout: DWORD Relationship, DWORD Size, then PROCESSOR_RELATIONSHIP (BYTE Flags, BYTE EfficiencyClass, BYTE Reserved[20], WORD GroupCount, GROUP_AFFINITY GroupMask[GroupCount]). Each GROUP_AFFINITY is a pointer-sized KAFFINITY Mask, WORD Group, and WORD Reserved[3].
Raises:
| Type | Description |
|---|---|
ValueError
|
If the buffer is malformed. |
Source code in zeus/device/cpu/emi.py
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 | |
get_current_emi_cpu_index
get_current_emi_cpu_index()
Return the EMI CPU index of the package the calling thread is running on.
This is the EMI counterpart of get_current_rapl_zone_id in the RAPL module:
the returned index can be passed as a cpu_indices entry to only measure the
CPU package the current thread is running on.
The current logical processor (processor group and within-group number) is
resolved with GetCurrentProcessorNumberEx and mapped to a package index
with GetLogicalProcessorInformationEx. Package records are assumed to be
enumerated in the same order as the EMI RAPL_Package{N} channel numbering.
Note
The scheduler can migrate threads across packages at any time. To prevent
this from happening during monitoring, pin the process to specific CPUs
(e.g., with SetProcessAffinityMask or start /affinity).
Source code in zeus/device/cpu/emi.py
703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 | |
emi_is_available
cached
emi_is_available()
Return True if CPU energy can be measured through EMI on this system.
A device only counts as usable if it exposes a RAPL-style package channel
(RAPL_Package{N}_PKG), since EMI is also used for other kinds of energy
meters (e.g., battery rails) that do not map to CPU packages.
Source code in zeus/device/cpu/emi.py
752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 | |