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

First paparazzi test in module takes too long time #1662

Open
zhkvdm opened this issue Oct 30, 2024 · 12 comments
Open

First paparazzi test in module takes too long time #1662

zhkvdm opened this issue Oct 30, 2024 · 12 comments
Labels
bug Something isn't working waiting on user Waiting on information from OP

Comments

@zhkvdm
Copy link

zhkvdm commented Oct 30, 2024

Description
We have multimodule android project. Every module contains some different paparazzi tests.
First launchable test method in first test class always takes too long time. It runs in ~20s. The next tests takes 0.5 - 2s.
The same in the different modules.
What's the cause of the freeze? How to speed up tests launch?

Steps to Reproduce
Run paparazzi tests with multiple test methods for whole module. Use gradle task ./gradlew :feature:verifyPaparazziDebug

Additional information:

  • Paparazzi Version: 1.3.4
  • OS: macOS / Linux
  • Compile SDK: 34
  • Gradle Version: Gradle 8.9
  • Android Gradle Plugin Version: 8.5.2

Screenshots
Test reports:
1
Image
Image

2
Image
Image

@zhkvdm zhkvdm added the bug Something isn't working label Oct 30, 2024
@geoff-powell
Copy link
Collaborator

Do you mind providing a sample project that reproduces the issue?

@geoff-powell geoff-powell added the waiting on user Waiting on information from OP label Oct 30, 2024
@zhkvdm
Copy link
Author

zhkvdm commented Oct 30, 2024

Do you mind providing a sample project that reproduces the issue?

I can't share this project, it's prohibited. But I can try to reproduce this issue at sample project

@jrodbx
Copy link
Collaborator

jrodbx commented Nov 1, 2024

First launchable test method in first test class always takes too long time. It runs in ~20s. The next tests takes 0.5 - 2s.
The same in the different modules.
What's the cause of the freeze? How to speed up tests launch?

The first test bootstraps Layoutlib via Bridge.init and statically caches it for subsequent runs, which explain why you notice a drop after the first test.

However, ~20s is high and I've never seen this before. I suspect you may just be running the tests with a conservative heap size; if so, bumping the max heap size should be enough to fix this.

@zhkvdm
Copy link
Author

zhkvdm commented Nov 1, 2024

First launchable test method in first test class always takes too long time. It runs in ~20s. The next tests takes 0.5 - 2s.
The same in the different modules.
What's the cause of the freeze? How to speed up tests launch?

The first test bootstraps Layoutlib via Bridge.init and statically caches it for subsequent runs, which explain why you notice a drop after the first test.

However, ~20s is high and I've never seen this before. I suspect you may just be running the tests with a conservative heap size; if so, bumping the max heap size should be enough to fix this.

Okay, thanks for reply. Is it possible to cache and share Layoutlib between all modules? Now each module init Layoutlib when running tests.

@jrodbx
Copy link
Collaborator

jrodbx commented Nov 6, 2024

Is it possible to cache and share Layoutlib between all modules?

This is a Gradle design issue. Each module has its own test task, which I believe runs in its own process via the test runner. If I'm understanding this correctly, then the answer to your question would be "no".

What's your current CI heap size? Have you tried increasing it?

@zhkvdm
Copy link
Author

zhkvdm commented Nov 7, 2024

Is it possible to cache and share Layoutlib between all modules?

This is a Gradle design issue. Each module has its own test task, which I believe runs in its own process via the test runner. If I'm understanding this correctly, then the answer to your question would be "no".

What's your current CI heap size? Have you tried increasing it?

We run tests in docker container with params --memory=42g --cpus="8" Xmx25

@zhkvdm
Copy link
Author

zhkvdm commented Nov 14, 2024

I have tried an android screenshot testing (https://developer.android.com/studio/preview/compose-screenshot-testing).
It works faster than paparazzi, but it should use the same mechanics, I think.
Image

@zhkvdm
Copy link
Author

zhkvdm commented Nov 14, 2024

I have created a new empty project with 2 screens and 6 paparazzi tests.
The test takes 3s on initialization. Is it ok?
Image
Image

@nick2525
Copy link

@jrodbx I posted a proposal to gradle gradle/gradle#31332 so that there is a way to bypass this restriction

@nick2525
Copy link

Gradle recommend to use build
services https://docs.gradle.org/current/userguide/build_services.html

@zhkvdm
Copy link
Author

zhkvdm commented Nov 25, 2024

First launchable test method in first test class always takes too long time. It runs in ~20s. The next tests takes 0.5 - 2s.
The same in the different modules.
What's the cause of the freeze? How to speed up tests launch?

The first test bootstraps Layoutlib via Bridge.init and statically caches it for subsequent runs, which explain why you notice a drop after the first test.

However, ~20s is high and I've never seen this before. I suspect you may just be running the tests with a conservative heap size; if so, bumping the max heap size should be enough to fix this.

How coulid I use build_services to store Layoutlib instance for all runs?

@nick2525
Copy link

Schematically then something like this, but I have not studied the implementation of Paparazzi

abstract class LayoutLibService : BuildService<BuildServiceParameters.None> {
   private val layoutlib: BridgeRenderSession = initLayoutLib()
   private val lock = ReentrantLock()

   fun renderView(view: View, deviceConfig: DeviceConfig): BufferedImage {
       lock.withLock {
           return layoutlib.render(
               view = view,
               width = deviceConfig.screenWidth,
               height = deviceConfig.screenHeight,
               density = deviceConfig.density,
           )
       }
   }
}

abstract class PaparazziTask @Inject constructor() : DefaultTask() {
   @get:Internal 
   abstract val layoutLibService: Property<LayoutLibService>

   @TaskAction 
   fun execute() {
       val composeView = AndroidComposeView(context)
       composeView.setContent {
          
       }
       
       val image = layoutLibService.get().renderView(
           view = composeView,
           deviceConfig = DeviceConfig.PIXEL_5
       )
      
   }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working waiting on user Waiting on information from OP
Projects
None yet
Development

No branches or pull requests

4 participants