compose-multiplatform icon indicating copy to clipboard operation
compose-multiplatform copied to clipboard

Performance issues(missing frames) on LazyColum

Open xinzhengzhang opened this issue 11 months ago • 33 comments

Describe the problem

Bad performance on LazyColum( There is no problem with using Colum ) and the content of the screen does not move with the hand (latency)

  • Have you noticed any patterns or specific circumstances under which the problem occurs? In both implementations, I used the Instruments tool Allocation and Animation Hitches and Time Profiler. I also tried grab the metal profile. It's all subtle levels. It doesn't seem to be a gpu performance problem. I feel like it's still a cpu problem. The data performance of the two methods is basically the same, but the actual touch is obviously felt with LazyColum jank.

Affected platforms Select one of the platforms below:

  • iOS

Versions

  • Kotlin version: 1.9.20
  • Compose Multiplatform version: 1.6.0
  • OS version(s) (required for Desktop and iOS issues): iOS 17.3.1
  • OS architecture (x86 or arm64): arm64
  • Device: iPhone 13

Sample code

// kotlin
fun getDemoViewController(isIdle: (Boolean) -> Unit): UIViewController {
    return ComposeUIViewController(
        content = {
            LazyColumn(userScrollEnabled = true, modifier = Modifier.fillMaxSize()) {
                items((0..100).toList(), { it }) { index ->
                    Text("Item $index", style = TextStyle(fontSize = 30.sp), modifier = Modifier.height(150.dp))
                }
            }

            // no problem using Column
//            Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())) {
//                (0..100).forEach { index ->
//                    Text(
//                        "Item $index",
//                        style = TextStyle(fontSize = 30.sp),
//                        modifier = Modifier.height(150.dp)
//                    )
//                }
//            }

        }
    )
}

//swift
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
  var window: UIWindow?

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    window = UIWindow(frame: UIScreen.main.bounds)
    window?.makeKeyAndVisible()
    window?.rootViewController = UINavigationController(rootViewController: Compose_view_iosKt.getDemoViewController { _ in})
    window?.backgroundColor = .white
    return true
  }
}

Video https://drive.google.com/file/d/1pekBo5D5OI-rkMHCb7byMYbAnsdXcz_c/view?usp=share_link

Profiling data https://drive.google.com/drive/folders/1yndeXWYojDAoYxiZoraq-HVajq0HbbcX?usp=share_link

xinzhengzhang avatar Mar 06 '24 13:03 xinzhengzhang

Bad performance on LazyColum( There is no problem with using Colum)

@elijah-semyonov, could you check it on your device, when you have time? If we have a visible input lag with LazyColumn comparing to Column, it is worth to investigate/fix soon. I suspect a few things.

igordmn avatar Mar 07 '24 22:03 igordmn

Facing the same issue. The CPU consumption goes ~80% just with LazyColumn.

kasem-sm avatar Apr 01 '24 18:04 kasem-sm

I'll have a look

elijah-semyonov avatar Apr 02 '24 07:04 elijah-semyonov

Not related to performance, seems like a state update error, investigating further.

https://github.com/JetBrains/compose-multiplatform/assets/4167681/dfd5056a-1fd9-4432-ae3c-4e8bf902aadd

elijah-semyonov avatar Apr 02 '24 08:04 elijah-semyonov

Facing the same issue. The CPU consumption goes ~80% just with LazyColumn.

Not related to this issue, sorry! But the scroll lag is visible.

kasem-sm avatar Apr 02 '24 14:04 kasem-sm

Facing the same issue...

dangdo1 avatar Apr 09 '24 10:04 dangdo1

Facing the same issue, and when start screen recording the scroll behavior so smooth

kiethayqua avatar Apr 09 '24 13:04 kiethayqua

@m-sasha before your PR will be reviewed and merged, how can I patch the dependency for my project ?

kiethayqua avatar Apr 11 '24 04:04 kiethayqua

That would be difficult. Just wait for the first dev build after my PR is merged.

m-sasha avatar Apr 11 '24 07:04 m-sasha

@m-sasha thanks for your response

kiethayqua avatar Apr 11 '24 07:04 kiethayqua

Runs perfectly with the test at JetBrains/compose-multiplatform-core/pull/1260 but unfortunately the "visible jump" comes back when commenting out the LaunchedEffect(Unit) { ... }, it seems the while-loop in LaunchedEffect(Unit) { ... } results in something similar to screen recording on iOS, @m-sasha please have a furthur look.

tipsypotato avatar Apr 18 '24 13:04 tipsypotato

@tipsypotato Not sure I understand. In my reproducer, the LaunchedEffect(Unit){...} is what is driving the scrolling. Without that it would not scroll.

Can you post a reproducer where the jump is still visible? Is it only visible on iOS? Can you post a video?

m-sasha avatar Apr 18 '24 14:04 m-sasha

@m-sasha Thanks for reply

the LaunchedEffect(Unit){...} is what is driving the scrolling.

Yeah but we can also scroll it mannually. I did some further tests, the scrolling experience with LazyColumn is still far from Column when scrolling on a real iOS device, it happened both on iPhoneSE3 and iPhone13 while run perfectly on Android. You can check the iOS screen recording below:

https://github.com/JetBrains/compose-multiplatform/assets/40794760/9129160b-c190-4231-ba92-56b180a4c21e

reproducer code:

@Composable
fun TestLazyColumn() {
    Box(modifier = Modifier.fillMaxSize()) {
        Row {
            Column(
                modifier = Modifier
                    .fillMaxHeight()
                    .weight(1f)
                    .verticalScroll(rememberScrollState())
            ) {
                (0..100).forEach { index ->
                    Text(
                        "Column item $index",
                        style = TextStyle(fontSize = 30.sp),
                        modifier = Modifier.height(150.dp).fillMaxWidth().border(
                            width = 1.dp,
                            color = Color.Black
                        )
                    )
                }
            }


            LazyColumn(
                state = rememberLazyListState(),
                modifier = Modifier.fillMaxHeight().weight(1f)
            ) {
                items(100) { index ->
                    Text(
                        "LazyColumn item $index",
                        style = TextStyle(fontSize = 30.sp),
                        modifier = Modifier.height(150.dp).fillMaxWidth().border(
                            width = 1.dp,
                            color = Color.Black
                        )
                    )
                }
            }
        }
    }
}

tipsypotato avatar Apr 19 '24 04:04 tipsypotato

@elijah-semyonov I guess more investigation is needed.

m-sasha avatar Apr 19 '24 06:04 m-sasha

@m-sasha I'll have another look.

elijah-semyonov avatar Apr 19 '24 06:04 elijah-semyonov

I struggle to reproduce it on 11 Pro Max and 14 Pro after the fix. Can you use slomo camera from the other device to verify (to avoid observer effects such as ones that could be caused by screen recording)?

https://github.com/JetBrains/compose-multiplatform/assets/4167681/91867b71-5679-41e3-8c73-36bd5b1f2a0c

https://github.com/JetBrains/compose-multiplatform/assets/4167681/6b6ad933-68b7-494d-9dd0-9cfcae7fe83d

elijah-semyonov avatar Apr 19 '24 07:04 elijah-semyonov

I'm experiencing the same issue, along with an additional one. It will become apparent when you scroll up. https://github.com/JetBrains/compose-multiplatform/assets/36324542/79224172-abda-4e08-b95d-8ce4f75a6487

jnelle avatar Apr 22 '24 18:04 jnelle

@jnelle Can you describe what you think you see? I'm not sure what to focus on exactly.

elijah-semyonov avatar Apr 23 '24 06:04 elijah-semyonov

I think he means the list seems to scroll to a random far position sometimes. But this is a different issue, possibly a bug in the user code. Please post a reproducer in a new issue.

m-sasha avatar Apr 23 '24 07:04 m-sasha

@elijah-semyonov In your second slomo video 14_pro.mov, the stutter happens at 0:09, 0:13, 0:23 and 0:26, and after several attempts with my reproducer, I noticed the stutter unexpectedly happens on Column when scrolling both at the sametime, while when scrolling the Column or the LazyColumn only, it seems the stutter only happens with LazyColumn.

tipsypotato avatar Apr 23 '24 08:04 tipsypotato

@tipsypotato Yeah, it's a debug build. Release build is much better (though can also have occasional stutters due to GC). Can you check if you have this behavior on release builds?

elijah-semyonov avatar Apr 23 '24 09:04 elijah-semyonov

@elijah-semyonov I'm facing the performance issues when I scroll down and also when I scroll up the list skips random positions.

Here is the reproducible code:

         is UiState.Success -> {
                    LazyColumn(modifier = Modifier.padding(innerPadding)) {
                        items(count = (uiState as UiState.Success<MainFeedResponse>).data.clips.size) {
                            Card(
                                Modifier.fillMaxWidth(),
                                shape = RoundedCornerShape(16.dp),
                                ) {
                                Image(
                                    painter = rememberImagePainter(
                                        (uiState as UiState.Success<MainFeedResponse>).data.clips[it].image
                                    ),
                                    contentDescription = "image",
                                )
                                Text((uiState as UiState.Success<MainFeedResponse>).data.clips[it].title)

                            }

                        }
                    }

                }

You'll find the repository here:

https://github.com/Nelle-Bendlage-IT/MassengeschmackTV

jnelle avatar Apr 23 '24 09:04 jnelle

@jnelle Thanks, I'll have a look!

elijah-semyonov avatar Apr 23 '24 09:04 elijah-semyonov

@elijah-semyonov I'm also facing the performance (stutters) issues on my Pixel 6 Pro, but it could be possible that this is caused from debug build. But the scroll behavior is also wrong but not the same as one iOS.

https://github.com/JetBrains/compose-multiplatform/assets/36324542/8501b99b-f5d9-4f8d-9b63-7a70fc5ae71f

jnelle avatar Apr 23 '24 10:04 jnelle

@jnelle We don't have an ownership over Android implementation. Could you please file an issue to Google Compose Issue tracker and paste a link here?

elijah-semyonov avatar Apr 23 '24 10:04 elijah-semyonov

@tipsypotato Yeah, it's a debug build. Release build is much better (though can also have occasional stutters due to GC). Can you check if you have this behavior on release builds?

@elijah-semyonov It still happens with release build on iOS, the stutters are frequent and subtle, but still very noticeable compared to Column. Our project uses lots of LazyColumn, so it would be very appreciated if you could give it a further look!

tipsypotato avatar Apr 23 '24 10:04 tipsypotato

@tipsypotato Apart from the issues you've noticed on my slowmo video, do you see something else? I'm trying to figure out if it's yet another lazy-column bug that we are not aware of (like the initially reported one), or general performance issues, which we are already working on.

elijah-semyonov avatar Apr 29 '24 08:04 elijah-semyonov

@elijah-semyonov add the code below to TestLazyColumn in the reproduce code above, the lazy-column performance issue will be gone.

LaunchedEffect(Unit) {
    while (true) {
        withFrameMillis {}
    }
}

tipsypotato avatar May 11 '24 04:05 tipsypotato

@tipsypotato this code snippet makes me think that it's probably related to https://github.com/JetBrains/compose-multiplatform-core/pull/1356

MatkovIvan avatar May 13 '24 16:05 MatkovIvan

@MatkovIvan As https://github.com/JetBrains/compose-multiplatform-core/pull/1356 is merged, any chance to have a try with a dev-release?

xiaozhikang0916 avatar May 15 '24 03:05 xiaozhikang0916