Skip to content

SDImageWebPCoder extremely slow #111

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

Closed
BuffBu opened this issue Jun 12, 2024 · 1 comment
Closed

SDImageWebPCoder extremely slow #111

BuffBu opened this issue Jun 12, 2024 · 1 comment

Comments

@BuffBu
Copy link

BuffBu commented Jun 12, 2024

I want to use WebP format for animations instead of GIFs. However, I've noticed that SDImageWebPCoder is significantly slower, with a performance gap of tens of times compared to GIFs and the system decoder available on iOS 14.

Below are my test cases and their results. Since we still have a large user base on iOS versions below 14, could you please advise on whether SDImageWebPCoder can be optimized?

final class ImagePerformanceTestCase: XCTestCase {
    
    var testAnimView = SDAnimatedImageView()

    override func setUpWithError() throws {
        super.setUp()
        SDImageCodersManager.shared.addCoder(SDImageWebPCoder.shared)
    }
    
    @available(iOS 14.0, *)
    func testAWebpDecodingPerformance() throws {
        guard let webPUrl = Bundle.main.url(forResource: "cubew", withExtension: "webp"),
              let webPData = try? Data(contentsOf: webPUrl) else {
            XCTFail("Failed to load Webp image data.")
            return
        }
        print("webp图片大小\(webPData.count)")
        // 测试解码性能
        measure {
            for _ in 0 ..< 10 {
                var img = SDImageAWebPCoder.shared.decodedImage(with: webPData, options: nil)
            }
            //testAnimView.sd_setImage(with:URL(string:"https://isparta.github.io/compare-webp/image/gif_webp/gif/1.gif"))
        }
    }
    
    
    func testWebPDecodingPerformance() throws {
        guard let webPUrl = Bundle.main.url(forResource: "cubew", withExtension: "webp"),
              let webPData = try? Data(contentsOf: webPUrl) else {
            XCTFail("Failed to load WebP image data.")
            return
        }
        print("webp图片大小\(webPData.count)")
        // 测试解码性能
        measure {
            for _ in 0 ..< 10 {
                var img = SDImageWebPCoder.shared.decodedImage(with: webPData, options: nil)
            }
            //testAnimView.sd_setImage(with:URL(string: "https://isparta.github.io/compare-webp/image/gif_webp/webp/1.webp"))
        }
    }

    func testGIFDecodingPerformance() throws {
        guard let gifUrl = Bundle.main.url(forResource: "cube", withExtension: "gif"),
              let gifData = try? Data(contentsOf: gifUrl) else {
            XCTFail("Failed to load GIF image data.")
            return
        }
        print("gif图片大小\(gifData.count)")
        // 测试解码性能
        measure {
            for _ in 0 ..< 10 {
                 var img = SDImageGIFCoder.shared.decodedImage(with: gifData, options: nil)
            }
            //testAnimView.sd_setImage(with:URL(string:"https://isparta.github.io/compare-webp/image/gif_webp/gif/1.gif"))
        }
    }
}

Test Case '-[image_Tests.ImagePerformanceTestCase testAWebpDecodingPerformance]' started.
webp图片大小380850
/Users/100010/test/.demo/features/test_ios/11.1.8/common/image_ios/Example/image/ImagePerformanceTestCase.swift:37: Test Case '-[image_Tests.ImagePerformanceTestCase testAWebpDecodingPerformance]' measured [Time, seconds] average: 0.034, relative standard deviation: 124.017%, values: [0.159663, 0.025849, 0.020243, 0.018986, 0.019030, 0.018984, 0.018927, 0.018926, 0.019007, 0.018933], performanceMetricID:com.apple.XCTPerformanceMetric_WallClockTime, baselineName: "", baselineAverage: , polarity: prefers smaller, maxPercentRegression: 10.000%, maxPercentRelativeStandardDeviation: 10.000%, maxRegression: 0.100, maxStandardDeviation: 0.100
Test Case '-[image_Tests.ImagePerformanceTestCase testAWebpDecodingPerformance]' passed (0.623 seconds).
Test Case '-[image_Tests.ImagePerformanceTestCase testGIFDecodingPerformance]' started.
gif图片大小890847
/Users/100010/test/.demo/features/test_ios/11.1.8/common/image_ios/Example/image/ImagePerformanceTestCase.swift:70: Test Case '-[image_Tests.ImagePerformanceTestCase testGIFDecodingPerformance]' measured [Time, seconds] average: 0.032, relative standard deviation: 41.455%, values: [0.071205, 0.030790, 0.027024, 0.027092, 0.027007, 0.027131, 0.027023, 0.026939, 0.026912, 0.026888], performanceMetricID:com.apple.XCTPerformanceMetric_WallClockTime, baselineName: "", baselineAverage: , polarity: prefers smaller, maxPercentRegression: 10.000%, maxPercentRelativeStandardDeviation: 10.000%, maxRegression: 0.100, maxStandardDeviation: 0.100
Test Case '-[image_Tests.ImagePerformanceTestCase testGIFDecodingPerformance]' passed (0.572 seconds).
Test Case '-[image_Tests.ImagePerformanceTestCase testWebPDecodingPerformance]' started.
webp图片大小380850

/Users/100010/test/.demo/features/test_ios/11.1.8/common/image_ios/Example/image/ImagePerformanceTestCase.swift:54: Test Case '-[image_Tests.ImagePerformanceTestCase testWebPDecodingPerformance]' measured [Time, seconds] average: 2.249, relative standard deviation: 1.178%, values: [2.328468, 2.235940, 2.237927, 2.241540, 2.241171, 2.239154, 2.238738, 2.246966, 2.241613, 2.242533], performanceMetricID:com.apple.XCTPerformanceMetric_WallClockTime, baselineName: "", baselineAverage: , polarity: prefers smaller, maxPercentRegression: 10.000%, maxPercentRelativeStandardDeviation: 10.000%, maxRegression: 0.100, maxStandardDeviation: 0.100
Test Case '-[image_Tests.ImagePerformanceTestCase testWebPDecodingPerformance]' passed (22.747 seconds).
Test Suite 'ImagePerformanceTestCase' passed at 2024-06-12 21:01:16.642.
Executed 3 tests, with 0 failures (0 unexpected) in 23.942 (23.942) seconds
Test Suite 'image_Tests.xctest' passed at 2024-06-12 21:01:16.643.
Executed 3 tests, with 0 failures (0 unexpected) in 23.942 (23.942) seconds
Test Suite 'Selected tests' passed at 2024-06-12 21:01:16.643.
Executed 3 tests, with 0 failures (0 unexpected) in 23.942 (23.943) seconds

@BuffBu BuffBu closed this as completed Nov 26, 2024
@dreampiggy
Copy link
Contributor

dreampiggy commented Nov 26, 2024

In history, the AWebPCoder (come from Apple's ImageIO framework) is slower, because it always re-decode the previous frame, if the animted webp using mux feature and blending feature.

See my feedback radar to Apple:

image

We notice that from iOS 14/macOS 11, ImageIO provide the native WebP/AWebP image fromat support, and we ship the version which provide the support for this.

However, during some performance test, we found that using Image/IO's API `CGImageSourceCreateImageAtIndex` to decode an large AWebP image, the larger frame index we query, the longer decoding time we spent. Which will cause some animation playback so laggy.

Which means:

Frame Index | Decoding Time spent
0 | 0.01
1 | 0.02
2 | 0.03
...
100 | 1.00


We try to find the reason, and found Image/IO use libwebp from Google for codec. However, the animated WebP is a format which use IPPP. When Image/IO decode next frame, it does not save the context from previous frame, and re-construct anything. This cause bad performance.

Compared to Image/IO, we develop a AWebP decoder which supports to keep the context, source code available here: https://github.com/SDWebImage/SDWebImageWebPCoder

We try to do the performance test between Image/IO and our AWebP decoder, here is the result:

Test Image: https://p1-ppx.byteimg.com/img/tos-cn-i-0000/424e830d3b5447b8802b2ebd900f90e3~tpl-1_q30_492x480.webp
Result: See video from attachment.
Demo Project: Sorry I just use our lib's Example for reproduce. You can use that SDWebImage.xcodeworkspace and run `SDWebImage iOS Demo` to see the compare result. 

I think you can re-test again, with the reproducable and standard sample (not just single cases)

Or you can check my 4 years ago video:

https://northamerica-1.object-storage.apple.com/v01/FR/7709/4281/0000/16226918/SDWebImage.zip?response-content-disposition=attachment&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=MKIA0879Y5FEZQ0RYD6Z%2F20241126%2Fnorthamerica-1%2Fs3%2Faws4_request&X-Amz-Date=20241126T082242Z&X-Amz-Expires=15&X-Amz-SignedHeaders=host&X-Amz-Signature=a919414ff29fb7be650d59e7fe6332a6cd8a7590d96e8e7ea7616b9463a6123d

https://northamerica-1.object-storage.apple.com/v01/FR/7709/4281/0000/16226917/AWeP%20Decode%20Compare%20ImageIO%20And%20SDWebImageWebPCoder.mov?response-content-disposition=attachment&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=MKIA0879Y5FEZQ0RYD6Z%2F20241126%2Fnorthamerica-1%2Fs3%2Faws4_request&X-Amz-Date=20241126T082241Z&X-Amz-Expires=15&X-Amz-SignedHeaders=host&X-Amz-Signature=1ecf0e08717a501145fc1cac9a5300dee26734f72c35b847fd582a99ce3be8c9

It's possible that Apple's Media team optimize for this case in iOS releases during the 4 years, but I haven't have time to test again

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

No branches or pull requests

2 participants