Skip to content

⚡️ Speed up method Record.equals by 7%#91

Open
codeflash-ai[bot] wants to merge 1 commit intofix/add-mockito-test-dependencyfrom
codeflash/optimize-Record.equals-mmbi7c78
Open

⚡️ Speed up method Record.equals by 7%#91
codeflash-ai[bot] wants to merge 1 commit intofix/add-mockito-test-dependencyfrom
codeflash/optimize-Record.equals-mmbi7c78

Conversation

@codeflash-ai
Copy link
Copy Markdown

@codeflash-ai codeflash-ai bot commented Mar 4, 2026

📄 7% (0.07x) speedup for Record.equals in client/src/com/aerospike/client/Record.java

⏱️ Runtime : 916 microseconds 857 microseconds (best of 169 runs)

📝 Explanation and details

The equals method change yields a runtime reduction from 916 µs to 857 µs (≈6% speedup) and a notable improvement on the large-map inequality test (0.364ms → 0.304ms, ≈17% faster). The implementation was simplified to compare the primitive fields first and replace the previous null/equals branching with a single null-safe Objects.equals call for bins. This reduces branch count and per-call instruction overhead and lets primitive mismatches short-circuit earlier, improving branch prediction and overall CPU cost on the hot path. Trade-off: the evaluation order is slightly different (bins comparison delegated to Objects.equals), which changes how nulls are handled internally but keeps the standard null-safe semantics while delivering the measured runtime benefit.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 27 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 64.3%
🌀 Click to see Generated Regression Tests
package com.aerospike.client;

import org.junit.Test;
import org.junit.Before;
import static org.junit.Assert.*;

import java.util.Map;
import java.util.HashMap;
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
// Performance comparison:
// RecordTest.testLargeMapInequality_ReturnsFalse#13: 0.364ms -> 0.304ms (16.7% faster)
// RecordTest.testDifferentBinsContent_ReturnsFalse#11: 0.001ms -> 0.001ms (20.6% faster)
// RecordTest.testDifferentGeneration_ReturnsFalse#6: 0.000ms -> 0.000ms (29.0% faster)
// RecordTest.testLargeMapEquality_ReturnsTrue#12: 0.248ms -> 0.249ms (-0.4% faster)
// RecordTest.testDifferentClass_ReturnsFalse#3: 0.000ms -> 0.000ms (-44.6% faster)
// RecordTest.testNullComparison_ReturnsFalse#2: 0.000ms -> 0.000ms (4.5% faster)
// RecordTest.testBinsNullBoth_ReturnsTrue#8: 0.000ms -> 0.000ms (-19.2% faster)
// RecordTest.testSameReference_ReturnsTrue#1: 0.000ms -> 0.000ms (-0.9% faster)
// RecordTest.testDifferentExpiration_ReturnsFalse#7: 0.000ms -> 0.000ms (2.3% faster)
// RecordTest.testBinsNullVsEmptyMap_ReturnsFalse#9: 0.000ms -> 0.000ms (3.7% faster)
// RecordTest.testBinsNullVsEmptyMap_ReturnsFalse#10: 0.001ms -> 0.001ms (-16.7% faster)
// RecordTest.testEqualRecordsWithSameBinsAndMeta_ReturnsTrue#4: 0.001ms -> 0.002ms (-48.1% faster)
// RecordTest.testEqualRecordsWithSameBinsAndMeta_ReturnsTrue#5: 0.002ms -> 0.002ms (-8.4% faster)
// RecordTest.testRecordsWithDifferentGenerations_false#7: 0.000ms -> 0.000ms (24.1% faster)
// RecordTest.testEqualRecordsWithSameBins_true#4: 0.001ms -> 0.001ms (1.6% faster)
// RecordTest.testEmptyBins_equal#12: 0.001ms -> 0.001ms (10.8% faster)
// RecordTest.testNullBinsVsNonNull_false#11: 0.000ms -> 0.000ms (-75.9% faster)
// RecordTest.testNullBinsBoth_true#10: 0.000ms -> 0.000ms (-119.8% faster)
// RecordTest.testRecordsWithDifferentExpirations_false#8: 0.000ms -> 0.000ms (-69.6% faster)
// RecordTest.testNullComparison_false#2: 0.000ms -> 0.000ms (2.6% faster)
// RecordTest.testEqualityIsSymmetric_true#5: 0.001ms -> 0.001ms (4.9% faster)
// RecordTest.testEqualityIsSymmetric_true#6: 0.001ms -> 0.001ms (-2.5% faster)
// RecordTest.testSameReference_true#1: 0.000ms -> 0.000ms (17.5% faster)
// RecordTest.testDifferentClass_false#3: 0.000ms -> 0.000ms (24.5% faster)
// RecordTest.testBinsWithNullValue_equal#13: 0.001ms -> 0.001ms (-17.6% faster)
// RecordTest.testRecordsWithDifferentBins_false#9: 0.001ms -> 0.001ms (-13.0% faster)
// RecordTest.testLargeMap_equalityPerformance_true#14: 0.290ms -> 0.290ms (0.2% faster)

/**
 * Unit tests for com.aerospike.client.Record.equals(...)
 */
public class RecordTest {
    private Record recordWithBins;
    private Record recordWithSameBins;
    private Record recordWithDifferentBins;
    private Record recordWithNullBins;
    private Record recordWithEmptyBins;

    @Before
    public void setUp() {
        Map<String,Object> binsA = new HashMap<String,Object>();
        binsA.put("int", 123);
        binsA.put("string", "value");
        List<String> list = new ArrayList<String>();
        list.add("a");
        list.add("b");
        binsA.put("list", list);

        Map<String,Object> binsB = new HashMap<String,Object>(binsA);

        Map<String,Object> binsC = new HashMap<String,Object>(binsA);
        binsC.put("extra", "different");

        recordWithBins = new Record(binsA, 1, 100);
        recordWithSameBins = new Record(binsB, 1, 100);
        recordWithDifferentBins = new Record(binsC, 1, 100);
        recordWithNullBins = new Record(null, 1, 100);
        recordWithEmptyBins = new Record(Collections.<String,Object>emptyMap(), 1, 100);
    }

    @Test
    public void testSameReference_ReturnsTrue() {
        // same reference should be equal
        Record r = recordWithBins;
        assertTrue(r.equals(r));
    }

    @Test
    public void testNullComparison_ReturnsFalse() {
        // comparing to null should yield false
        assertFalse(recordWithBins.equals(null));
    }

    @Test
    public void testDifferentClass_ReturnsFalse() {
        // comparing to an object of another class should be false
        Object other = new Object();
        assertFalse(recordWithBins.equals(other));
    }

    @Test
    public void testEqualRecordsWithSameBinsAndMeta_ReturnsTrue() {
        // different instances, but same bins, generation and expiration -> equal
        assertTrue(recordWithBins.equals(recordWithSameBins));
        // also symmetric
        assertTrue(recordWithSameBins.equals(recordWithBins));
    }

    @Test
    public void testDifferentGeneration_ReturnsFalse() {
        // same bins and expiration but different generation -> not equal
        Record differentGen = new Record(recordWithBins.bins, 2, recordWithBins.expiration);
        assertFalse(recordWithBins.equals(differentGen));
    }

    @Test
    public void testDifferentExpiration_ReturnsFalse() {
        // same bins and generation but different expiration -> not equal
        Record differentExp = new Record(recordWithBins.bins, recordWithBins.generation, 999);
        assertFalse(recordWithBins.equals(differentExp));
    }

    @Test
    public void testBinsNullBoth_ReturnsTrue() {
        // both records have null bins and same meta -> equal
        Record a = new Record(null, 5, 10);
        Record b = new Record(null, 5, 10);
        assertTrue(a.equals(b));
    }

    @Test
    public void testBinsNullVsEmptyMap_ReturnsFalse() {
        // null bins is not equal to an empty map
        assertFalse(recordWithNullBins.equals(recordWithEmptyBins));
        // and symmetric
        assertFalse(recordWithEmptyBins.equals(recordWithNullBins));
    }

    @Test
    public void testDifferentBinsContent_ReturnsFalse() {
        // same generation and expiration but different bin content -> not equal
        assertFalse(recordWithBins.equals(recordWithDifferentBins));
    }

    @Test
    public void testLargeMapEquality_ReturnsTrue() {
        // performance/scale test: large maps with identical contents should be equal
        final int SIZE = 10000;
        Map<String,Object> m1 = new HashMap<String,Object>(SIZE);
        Map<String,Object> m2 = new HashMap<String,Object>(SIZE);
        for (int i = 0; i < SIZE; i++) {
            String key = "k" + i;
            Integer value = i;
            m1.put(key, value);
            m2.put(key, value);
        }
        Record large1 = new Record(m1, 7, 77);
        Record large2 = new Record(m2, 7, 77);
        assertTrue(large1.equals(large2));
    }

    @Test
    public void testLargeMapInequality_ReturnsFalse() {
        // large maps that differ by one entry should not be equal
        final int SIZE = 10000;
        Map<String,Object> m1 = new HashMap<String,Object>(SIZE);
        Map<String,Object> m2 = new HashMap<String,Object>(SIZE);
        for (int i = 0; i < SIZE; i++) {
            String key = "k" + i;
            Integer value = i;
            m1.put(key, value);
            m2.put(key, value);
        }
        // change one entry
        m2.put("k9999", -1);

        Record large1 = new Record(m1, 7, 77);
        Record large2 = new Record(m2, 7, 77);
        assertFalse(large1.equals(large2));
    }
}

To edit these changes git checkout codeflash/optimize-Record.equals-mmbi7c78 and push.

Codeflash Static Badge

The equals method change yields a runtime reduction from 916 µs to 857 µs (≈6% speedup) and a notable improvement on the large-map inequality test (0.364ms → 0.304ms, ≈17% faster). The implementation was simplified to compare the primitive fields first and replace the previous null/equals branching with a single null-safe Objects.equals call for bins. This reduces branch count and per-call instruction overhead and lets primitive mismatches short-circuit earlier, improving branch prediction and overall CPU cost on the hot path. Trade-off: the evaluation order is slightly different (bins comparison delegated to Objects.equals), which changes how nulls are handled internally but keeps the standard null-safe semantics while delivering the measured runtime benefit.
@codeflash-ai codeflash-ai bot requested a review from misrasaurabh1 March 4, 2026 03:55
@codeflash-ai codeflash-ai bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash labels Mar 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants