Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tests: pm: Adding tests based on new approach to PM testing. #80692

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

gbarkadiusz
Copy link
Collaborator

@gbarkadiusz gbarkadiusz commented Oct 31, 2024

  • Introduces two scripts abstract_power_monitor.py and pwsh_stm32l562.py.

  • Adds three new power management pytests based on a new approach.

SETUP

image
image

TESTS

pm.states: Verifies the transition to all available power states on stm32l562e_dk.

During the test, pytest detects each step and calculates the RMS (Root Mean Square) current for every detected state. The test then compares the calculated RMS values against the expected values, which have been determined manually through experimental observation

pm.residency_time: Tests the residency time of each power state.
This test evaluates the residency time of different power states on the stm32l562e_dk board.

pm.wakeup_timer: Tests the RTC alarm’s ability to wake the CPU from the lowest power state.

Each test calculates RMS current values for each detected state and compares them to expected values, which were manually set based on experimental data.

To Reproduce

  1. Configure the stm32l562e_dk board according to the instructions provided above.
  2. Connect both USB ports of the board to your host system. The board will appear as two separate targets:
    Power Monitor: e.g., /dev/ttyACM0 or /dev/serial/by-id/usb-STMicroelectronics_PowerShield__Virtual_ComPort_in_FS_Mode__FFFFFFFEFFFF-if00
    Target: e.g., /dev/ttyACM1 or /dev/serial/by-id/usb-STMicroelectronics_STLINK-V3_004##############39-if02
  3. Copy the path of the Power Monitor and update the <path_to_power_monitor> in the tests/subsys/pm/power_states/testcase.yaml file under the pytest_args section as follows:
    pytest_args: [--powershield=<path_to_power_monitor>]
  4. Run the following command to execute the test:
    twister --device-testing --device-serial <path_to_target> -p stm32l562e_dk -s <test_name> -x=CONFIG_BOOT_DELAY=500

@gbarkadiusz gbarkadiusz added the DNM This PR should not be merged (Do Not Merge) label Oct 31, 2024
@gbarkadiusz gbarkadiusz changed the title tests: pm: Adding tests based on a new approach to power management tests: pm: Adding tests based on new approach to PM testing. Oct 31, 2024
@gbarkadiusz gbarkadiusz force-pushed the topic/rfc/power_management branch 8 times, most recently from bb6e11e to cc760a2 Compare November 5, 2024 11:26
@gbarkadiusz gbarkadiusz linked an issue Nov 6, 2024 that may be closed by this pull request
@gbarkadiusz gbarkadiusz marked this pull request as ready for review November 14, 2024 09:38
data = current_measurement_output
# Empirical RMS values in mA with descriptive keys
rms_expected = {
"k_cpu_idle":57.0, # K_cpu_idle
Copy link
Collaborator

@hakehuang hakehuang Nov 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we move those expected data to a yaml file for different platform?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course we can, the good hint. Thank you.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PS: Btw, Please take a look. #80989. Feel free to share ideas or warries. :)

while (1) {
printk("\nGoing to k_cpu_idle.\n");
k_msleep(400);
printk("\nWake Up.\n");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we use this tests\subsys\pm\power_mgmt_soc\src\power_mgmt.c, instead of the sleep time?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know yet, let me see.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, get the information from the device tree is the way to go imho, otherwise it will not be portable and the previous comment is useless.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ceolin I added the use of DTS, is this what you meant?

@@ -0,0 +1,30 @@
# Copyright (c) 2024 Intel Corporation.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would this be better to move this function to scripts/pm/pm_helper.py, and rms is not the only implement, e.g. we can have average mean

@gbarkadiusz gbarkadiusz marked this pull request as draft November 25, 2024 14:49
@gbarkadiusz gbarkadiusz force-pushed the topic/rfc/power_management branch 3 times, most recently from f959bb2 to 980a943 Compare December 10, 2024 14:35
@gbarkadiusz gbarkadiusz force-pushed the topic/rfc/power_management branch 6 times, most recently from 1f00e48 to 69e3a4f Compare December 13, 2024 11:57
@gbarkadiusz gbarkadiusz force-pushed the topic/rfc/power_management branch 6 times, most recently from 2525c2f to dc18404 Compare January 10, 2025 13:43
@gbarkadiusz gbarkadiusz requested a review from hakehuang January 10, 2025 13:49
@gbarkadiusz
Copy link
Collaborator Author

@hakehuang I've moved the hardcoded expected value to the appropriate yaml file. Please take a look.

@gbarkadiusz gbarkadiusz marked this pull request as ready for review January 10, 2025 13:50
@gbarkadiusz gbarkadiusz force-pushed the topic/rfc/power_management branch from dc18404 to cbc99c3 Compare January 15, 2025 11:56
@gbarkadiusz gbarkadiusz removed the DNM This PR should not be merged (Do Not Merge) label Jan 15, 2025
hakehuang
hakehuang previously approved these changes Jan 16, 2025
Copy link
Collaborator

@hakehuang hakehuang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good

Comment on lines +25 to +26
pytest_args: [--powershield=<path_to>/STMicroelectronics_PowerShield__Virtual_ComPort,
--expected-values=<path_to>/stm32l562e_dk.yaml]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC these need to be set manually before testing, right ?

Any way we can spare the need for manual update ?
At least, <path_to>/stm32l562e_dk.yaml is rather static, so it looks reachable.
For <path_to>/STMicroelectronics_PowerShield__Virtual_ComPort maybe a dedicated twister configuration could be used or added ?

@bjarki-andreasen
Copy link
Collaborator

bjarki-andreasen commented Jan 24, 2025

I believe the approach in this PR is too highly coupled to pm power states, a specific power monitor, and a specific test case.

Measuring current/power or anything else is "generic", its measured in SI units, and can be performed by an "endless" variation of probes. I compare measuring power with "any probe" to flashing a board with "any runner", be it jlink, openocd, pyocd, or whatever.

I believe it can and should be as simple to define a testcase requiring power measurements as this
testcase.yaml:

tests:
  pm.power_states:
    harness: probe
    harness_config:
      measurements:
        - name: k_cpu_idle:
          rms: 56.0
        - name: state_0:
          rms: 56.0

The measurements could be anything, a mode, some peripheral being on, like a comparator in low power mode:

        - name: comp_low_power:
          rms: 56.0
        - name: comp_high_power:
          rms: 71.0

and that specific probes, like runners, should be defined like --probe stm_powershield and --probe-port /dev/ttyACM0 if required, to specify which probe to use for the test. See https://docs.zephyrproject.org/latest/develop/test/twister.html#running-tests-on-hardware for example. Any testsuite can be run for any board, with whatever flasher is available and supported.

This is important, as the test case should not depend on any specific probe, if one developer has a JouleScope, another has a Nordic PPK2, and a third has an stm_powershield, they should all be able to run the same testcase. We are measuring the same "generic" properties after all.

This PR keeps a bunch of this local, using pytest, but I don't think that is a nice, scalable approach to power measurements.

@nashif
Copy link
Member

nashif commented Jan 28, 2025

I believe the approach in this PR is too highly coupled to pm power states, a specific power monitor, and a specific test case.

agree this could be abstracted to support future probes and other measurements. We need to start somewhere though.

I believe it can and should be as simple to define a testcase requiring power measurements as this testcase.yaml:

tests:
  pm.power_states:
    harness: probe
    harness_config:
      measurements:
        - name: k_cpu_idle:
          rms: 56.0
        - name: state_0:
          rms: 56.0

The measurements could be anything, a mode, some peripheral being on, like a comparator in low power mode:

        - name: comp_low_power:
          rms: 56.0
        - name: comp_high_power:
          rms: 71.0

Ok, probably probe is a bit too generic for a harness name, but we could use a dedicated harness name for power measurements and still keep the underlying implementation using pytest and use the harness config for any probe related options.
Also moving expected results from a dedicated yaml file to testcase.yaml is fine.

@gbarkadiusz can you look into this? AFAIK that should be possible with the current implementation while allowing for future addition of probes.

@gbarkadiusz
Copy link
Collaborator Author

gbarkadiusz commented Jan 30, 2025

@nashif @bjarki-andreasen Regarding the proposal for a separate harness for power measurement, IIUC, Is it right to create a new harness that duplicates the functionality of pytest (which would lead to code duplication)? In fact, we can use the existing pytest harness to achieve our goal. We can simply extend its configuration to include additional details about the probe and port being used.

@bjarki-andreasen
Copy link
Collaborator

@nashif @bjarki-andreasen Regarding the proposal for a separate harness for power measurement, IIUC, Is it right to create a new harness that duplicates the functionality of pytest (which would lead to code duplication)? In fact, we can use the existing pytest harness to achieve our goal. We can simply extend its configuration to include additional details about the probe and port being used.

pytest is a generic framework, any harness could theoretically be implemented with pytest I believe, a custom harness would be purpose built, its less a question of duplication than it is simplicity of use :)

Copy link
Member

@ceolin ceolin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is looking good, I think that is a good start, even being target specific.

We need to start somewhere :) Overall comments but nothing major.

Thanks a lot for this effort.


Returns:
List[float]: An array of measured current values in amperes.
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering if that isn't generic enough to be the interface for this sort of test and not specific for stm32l56e_dk

Copy link
Collaborator Author

@gbarkadiusz gbarkadiusz Feb 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This allows us to easily extend the system to support other platforms without needing to rewrite the entire test logic. The goal is to keep the test interface flexible and adaptable to different devices.

self.target_voltage = round(voltage, 3)
return self.target_voltage
except ValueError:
logging.error("Error: Could not convert temperature value.")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

temperature ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Writing the library for PowerShield.py I implemented this functionality only for testing. If not necessary, I'll remove it.

logging.warning("No response for voltage command.")
return None

def get_temperature(self, unit: str = PowerShieldConf.TemperatureUnit.CELCIUS) -> float:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this being used anywhere ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, only for testing, showing that the firmware of PowerShield allows to read the value of temperature.

if len(x) < 1 or x == 0xF0:
self.acqComplete = True
return s.replace("\0", "").strip().replace("\r", "").replace("\n\n\n", "\n")
s += str(x, encoding='ascii', errors='ignore')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it missing an explicit return ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This loop should continue as long as data exists from the serial connection.

"""
Handle metadata end of acquisition message.
"""
# Read the next 4 bytes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 or 2 bytes ?

while True:
if self.dataQueue.empty() and bool(self.acqComplete):
outputFile.close()
return
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can't you just break it here ?

self.start_measurement()

# calculate the data
# self.get_measured_data(measure_unit)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't it be removed ?


static const struct device *rtc = DEVICE_DT_GET(DT_NODELABEL(rtc));

volatile k_tid_t my_tid;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why using volatile here ? shouldn't the scope be local too ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's right it has not to be a volatile variable. I used that attribute to be sure that this variable is not going to be optimized by compiler.

struct k_thread my_thread_data;
K_THREAD_STACK_DEFINE(my_stack_area, MY_STACK_SIZE);

void my_entry_point(void *, void *, void *)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

static void my_entry_point(void *arg1, void *arg2, void *arg3)


while (1) {
arch_nop();
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you have these loops ? you don't want the app to idle ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've noticed that the STM32L562E-DK board enters sleep mode without this loop, which causes issues with reconnecting and executing the next test.

Twister harness log.
DEBUG:twister_harness.device.factory: Get device type "hardware"
DEBUG:twister_harness.device.hardware_adapter: Opening serial connection for /dev/ttyACM1
DEBUG:twister_harness.device.hardware_adapter: Flashing command: west flash --skip-rebuild --build-dir <path_to>/twister-out/stm32l562e_dk_stm32l562xx/tests/subsys/pm/power_wakeup_timer/pm.power_wakeup_timer.pm_device --runner pyocd -- --dev-id=004800483137510D33333639
ERROR:twister_harness.device.hardware_adapter: Could not flash device None
DEBUG:twister_harness.device.hardware_adapter: Closed serial connection for /dev/ttyACM1

So, the quick fix was added this infinite loop.

Copy link
Collaborator Author

@gbarkadiusz gbarkadiusz Feb 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PS: Pyocd throws:

0003817 E Error while initing target: STLink error (9): Get IDCODE error [commander]

And then it has to be erased manually by:
pyocd erase --mass -t 'stm32l562qeixq' -O reset_type=hw -O connect_mode='under-reset'

@gbarkadiusz
Copy link
Collaborator Author

@ceolin Thank you for feedback, I applied your suggestions, please take a look again.

@nashif
Copy link
Member

nashif commented Feb 3, 2025

@nashif @bjarki-andreasen Regarding the proposal for a separate harness for power measurement, IIUC, Is it right to create a new harness that duplicates the functionality of pytest (which would lead to code duplication)? In fact, we can use the existing pytest harness to achieve our goal. We can simply extend its configuration to include additional details about the probe and port being used.

see #85033

Introduces scripts for powerShiled on stm32l562e_dk board.
Adds three new power management pytests based on a new approach.

Signed-off-by: Arkadiusz Cholewinski <[email protected]>
@gbarkadiusz
Copy link
Collaborator Author

Thank you @nashif for the suggestions. I've implemented the Power Harness, and here is the link #85130 to the POC Draft PR. Please have a look and let me know if this is what you had in mind for the additional harness implementation
@bjarki-andreasen FYI.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

RFC: New Testing Approach for Power Management Subsystem.
7 participants