Skip to content

⚡️ Speed up function pipeline by 8%#309

Open
codeflash-ai[bot] wants to merge 1 commit intoexperimentalfrom
codeflash/optimize-pipeline-mn6n1bxa
Open

⚡️ Speed up function pipeline by 8%#309
codeflash-ai[bot] wants to merge 1 commit intoexperimentalfrom
codeflash/optimize-pipeline-mn6n1bxa

Conversation

@codeflash-ai
Copy link
Copy Markdown

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

📄 8% (0.08x) speedup for pipeline in js/src/dataTransform.ts

⏱️ Runtime : 73.3 microseconds 68.2 microseconds (best of 100 runs)

📝 Explanation and details

The optimization hoists fns.length out of the loop condition into a pre-computed constant (const len), eliminating redundant property lookups on every iteration. The original profiler data shows the loop condition consumed 46.7% of runtime, and after caching the length, that overhead drops to 4.5% while the actual function invocation (result = fns[i](result)) becomes the dominant cost at 82.7%—the expected hot-path. This single-line change yields a 7% speedup with no behavioral trade-offs, as confirmed by all regression tests passing with consistent or improved timings.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 30 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
🌀 Click to see Generated Regression Tests
// @ts-nocheck
import { jest, describe, it, expect, beforeEach, afterEach, beforeAll, test } from '@jest/globals'
// function import (Jest - globals are available)
import { pipeline } from '../src/dataTransform';

describe('pipeline', () => {

    // Basic Test Cases
    describe('Basic functionality', () => {
        test('should handle normal numeric transformations in order', () => {
            // Start with 2; multiply by 3 then add 4 => (2 * 3) + 4 = 10
            const multiplyBy3 = (n) => n * 3;
            const add4 = (n) => n + 4;

            const result = pipeline(2, multiplyBy3, add4);

            expect(result).toBe(10);
        });

        test('should handle string transformations', () => {
            // Compose uppercase then suffix
            const toUpper = (s) => s.toUpperCase();
            const exclaim = (s) => `${s}!`;

            const result = pipeline('hello', toUpper, exclaim);

            expect(result).toBe('HELLO!');
        });

        test('should return the original object reference when no functions are provided', () => {
            // Objects should be returned by reference if no transforms applied
            const obj = { a: 1 };
            const result = pipeline(obj); // no functions

            expect(result).toBe(obj); // same reference
        });

        test('should produce new objects when functions return new references (immutability)', () => {
            // Ensure pipeline does not mutate the original unless the function does
            const original = { count: 1 };
            const incrementImmutable = (o) => ({ ...o, count: o.count + 1 });
            const doubleImmutable = (o) => ({ ...o, count: o.count * 2 });

            const result = pipeline(original, incrementImmutable, doubleImmutable);

            // original must not be mutated
            expect(original).toEqual({ count: 1 });
            // result should reflect the composed transforms: (1 + 1) * 2 = 4
            expect(result).toEqual({ count: 4 });
            // result must not be the same reference as original
            expect(result).not.toBe(original);
        });

        test('should allow transforms that change the runtime type (JS is dynamic)', () => {
            // Start with a number, convert to string, then append chars
            const addOne = (n) => n + 1;
            const toString = (n) => String(n);
            const appendBang = (s) => s + '!';

            const result = pipeline(1, addOne, toString, appendBang);

            expect(result).toBe('2!');
        });
    });

    // Edge Test Cases
    describe('Edge cases', () => {
        test('should handle null and undefined as initial values when functions can accept them', () => {
            // Functions that gracefully handle null/undefined
            const handleNull = (v) => (v == null ? 'was-null-or-undefined' : v);
            const append = (s) => `${s}-ok`;

            const resultNull = pipeline(null, handleNull, append);
            const resultUndefined = pipeline(undefined, handleNull, append);

            expect(resultNull).toBe('was-null-or-undefined-ok');
            expect(resultUndefined).toBe('was-null-or-undefined-ok');
        });

        test('should propagate errors thrown by a transform function', () => {
            // If any function throws, pipeline should propagate the exception
            const good = (n) => n + 1;
            const bad = () => {
                throw new Error('transform failed');
            };

            expect(() => pipeline(1, good, bad, good)).toThrow('transform failed');
        });

        test('should throw a TypeError if a non-function is passed among transforms', () => {
            // Passing a non-function (e.g., null) will cause a TypeError when invoked
            const incr = (n) => n + 1;

            expect(() => pipeline(0, incr, null)).toThrow(TypeError);
            expect(() => pipeline(0, undefined)).toThrow(TypeError);
            expect(() => pipeline(0, 123)).toThrow(TypeError);
        });

        test('should support in-place mutation transforms (functions that mutate and return the same reference)', () => {
            // A transform that mutates its input and returns it
            const obj = { value: 10 };
            const mutate1 = (o) => { o.value += 5; return o; };
            const mutate2 = (o) => { o.value *= 2; return o; };

            const result = pipeline(obj, mutate1, mutate2);

            // result should be same reference as obj and mutated accordingly: (10 + 5) * 2 = 30
            expect(result).toBe(obj);
            expect(result.value).toBe(30);
        });

        test('should execute functions in left-to-right order', () => {
            // Track order of execution via side effects
            const order = [];
            const a = (x) => { order.push('a'); return x + 'a'; };
            const b = (x) => { order.push('b'); return x + 'b'; };
            const c = (x) => { order.push('c'); return x + 'c'; };

            const result = pipeline('', a, b, c);

            expect(result).toBe('abc');
            expect(order).toEqual(['a', 'b', 'c']);
        });
    });

    // Large Scale Test Cases
    describe('Performance tests', () => {
        test('should handle a large number of small transforms correctly and efficiently', () => {
            // Create 500 simple increment functions and verify final value and call count.
            // Keep iterations under 1000 as requested.
            const COUNT = 500;
            const fns = [];
            // Use jest.fn wrappers to collect call counts
            for (let i = 0; i < COUNT; i++) {
                fns.push(jest.fn((n) => n + 1));
            }

            // Execute pipeline starting at 0; should increment COUNT times -> COUNT
            const result = pipeline(0, ...fns);

            expect(result).toBe(COUNT);

            // Ensure each transform was called exactly once and in order
            for (let i = 0; i < COUNT; i++) {
                expect(fns[i]).toHaveBeenCalledTimes(1);
            }
        });

        test('should handle larger payloads passed through a single transform (array of moderate size)', () => {
            // Keep data structure under 1000 elements (use 500).
            const SIZE = 500;
            const arr = Array.from({ length: SIZE }, (_, i) => i);

            // One transform that maps over the array (simulate heavier per-element work)
            const incrementAll = (a) => a.map((x) => x + 1);

            const result = pipeline(arr, incrementAll);

            // Verify correctness: first and last elements changed
            expect(result.length).toBe(SIZE);
            expect(result[0]).toBe(1);
            expect(result[SIZE - 1]).toBe(SIZE);
            // original should remain unchanged (map returns new array)
            expect(arr[0]).toBe(0);
            expect(arr[SIZE - 1]).toBe(SIZE - 1);
        });
    });

});
// @ts-nocheck
import { jest, describe, it, expect, beforeEach, afterEach, beforeAll, test } from '@jest/globals'
import { pipeline } from '../src/dataTransform';

describe('pipeline', () => {

    // Basic Test Cases
    describe('Basic functionality', () => {
        test('should return the same value when no functions are provided', () => {
            const value = 42;
            const result = pipeline(value);
            expect(result).toBe(42);  // 1.04μs -> 875ns (19.1% faster)
        });

        test('should apply a single function to the value', () => {
            const add5 = (x) => x + 5;
            const result = pipeline(10, add5);
            expect(result).toBe(15);  // 1.33μs -> 958ns (39.2% faster)
        });

        test('should apply multiple functions in sequence', () => {
            const add5 = (x) => x + 5;
            const multiply2 = (x) => x * 2;
            const subtract3 = (x) => x - 3;
            const result = pipeline(10, add5, multiply2, subtract3);
            expect(result).toBe(27); // ((10 + 5) * 2) - 3 = 27
        });

        test('should work with string transformations', () => {
            const toUpperCase = (str) => str.toUpperCase();
            const addExclamation = (str) => str + '!';
            const result = pipeline('hello', toUpperCase, addExclamation);
            expect(result).toBe('HELLO!');  // 1.96μs -> 1.50μs (30.5% faster)
        });

        test('should work with objects', () => {
            const obj = { value: 5 };
            const addProperty = (o) => ({ ...o, processed: true });
            const incrementValue = (o) => ({ ...o, value: o.value + 10 });
            const result = pipeline(obj, addProperty, incrementValue);
            expect(result).toEqual({ value: 15, processed: true });  // 2.12μs -> 2.00μs (6.25% faster)
        });

        test('should work with arrays', () => {
            const arr = [1, 2, 3];
            const doubleAll = (a) => a.map((x) => x * 2);
            const addTen = (a) => a.map((x) => x + 10);
            const result = pipeline(arr, doubleAll, addTen);
            expect(result).toEqual([12, 14, 16]);  // 1.38μs -> 1.29μs (6.51% faster)
        });

        test('should preserve type through pipeline', () => {
            const addOne = (x) => x + 1;
            const result = pipeline(5, addOne);
            expect(typeof result).toBe('number');  // 583ns -> 542ns (7.56% faster)
        });
    });

    // Edge Test Cases
    describe('Edge cases', () => {
        test('should handle zero as input value', () => {
            const add10 = (x) => x + 10;
            const result = pipeline(0, add10);
            expect(result).toBe(10);  // 541ns -> 541ns (0.000% faster)
        });

        test('should handle negative numbers', () => {
            const abs = (x) => Math.abs(x);
            const double = (x) => x * 2;
            const result = pipeline(-5, abs, double);
            expect(result).toBe(10);  // 1.46μs -> 1.25μs (16.7% faster)
        });

        test('should handle null as input value', () => {
            const identity = (x) => x;
            const result = pipeline(null, identity);
            expect(result).toBeNull();  // 500ns -> 500ns (0.000% faster)
        });

        test('should handle undefined as input value', () => {
            const identity = (x) => x;
            const result = pipeline(undefined, identity);
            expect(result).toBeUndefined();  // 500ns -> 500ns (0.000% faster)
        });

        test('should handle empty string', () => {
            const addText = (str) => str + 'text';
            const result = pipeline('', addText);
            expect(result).toBe('text');  // 625ns -> 583ns (7.20% faster)
        });

        test('should handle empty array', () => {
            const addElement = (arr) => [...arr, 'new'];
            const result = pipeline([], addElement);
            expect(result).toEqual(['new']);  // 1.00μs -> 958ns (4.38% faster)
        });

        test('should handle empty object', () => {
            const addKey = (obj) => ({ ...obj, key: 'value' });
            const result = pipeline({}, addKey);
            expect(result).toEqual({ key: 'value' });  // 1.50μs -> 1.25μs (20.0% faster)
        });

        test('should handle boolean values', () => {
            const negate = (b) => !b;
            const result = pipeline(true, negate);
            expect(result).toBe(false);  // 541ns -> 541ns (0.000% faster)
        });

        test('should handle NaN gracefully', () => {
            const identity = (x) => x;
            const result = pipeline(NaN, identity);
            expect(Number.isNaN(result)).toBe(true);  // 500ns -> 500ns (0.000% faster)
        });

        test('should handle Infinity', () => {
            const add1 = (x) => x + 1;
            const result = pipeline(Infinity, add1);
            expect(result).toBe(Infinity);  // 583ns -> 541ns (7.76% faster)
        });

        test('should handle function as value', () => {
            const fn = () => 42;
            const identity = (x) => x;
            const result = pipeline(fn, identity);
            expect(result).toBe(fn);  // 500ns -> 458ns (9.17% faster)
        });

        test('should handle symbol as value', () => {
            const sym = Symbol('test');
            const identity = (x) => x;
            const result = pipeline(sym, identity);
            expect(result).toBe(sym);  // 500ns -> 500ns (0.000% faster)
        });

        test('should work with a function that returns a different type', () => {
            const stringify = (x) => String(x);
            const result = pipeline(42, stringify);
            expect(result).toBe('42');  // 1.17μs -> 1.04μs (12.0% faster)
            expect(typeof result).toBe('string');
        });

        test('should handle functions that modify nested objects', () => {
            const obj = { nested: { value: 5 } };
            const updateNested = (o) => ({
                ...o,
                nested: { ...o.nested, value: o.nested.value * 2 }
            });
            const result = pipeline(obj, updateNested);
            expect(result.nested.value).toBe(10);  // 1.58μs -> 1.42μs (11.8% faster)
        });

        test('should handle large numbers', () => {
            const add = (x) => x + 1;
            const result = pipeline(Number.MAX_SAFE_INTEGER - 1, add);
            expect(result).toBe(Number.MAX_SAFE_INTEGER);  // 542ns -> 500ns (8.40% faster)
        });

        test('should handle float precision', () => {
            const add = (x) => x + 0.1;
            const subtract = (x) => x - 0.2;
            const result = pipeline(0.1, add, subtract);
            // Floating point should result in approximately 0
            expect(result).toBeCloseTo(0, 10);  // 875ns -> 708ns (23.6% faster)
        });
    });

    // Large Scale Test Cases
    describe('Performance tests', () => {
        test('should handle a large number of transformation functions', () => {
            // Create 100 simple increment functions
            const functions = Array.from({ length: 100 }, () => (x) => x + 1);
            const result = pipeline(0, ...functions);
            expect(result).toBe(100);  // 1.79μs -> 1.67μs (7.44% faster)
        });

        test('should handle complex transformations on large arrays', () => {
            const largeArray = Array.from({ length: 500 }, (_, i) => i);
            const double = (arr) => arr.map((x) => x * 2);
            const filter = (arr) => arr.filter((x) => x > 100);
            const sum = (arr) => ({ sum: arr.reduce((a, b) => a + b, 0) });
            const result = pipeline(largeArray, double, filter, sum);
            expect(result.sum).toBeGreaterThan(0);  // 22.4μs -> 21.4μs (4.67% faster)
            expect(typeof result.sum).toBe('number');
        });

        test('should handle deeply nested object transformations', () => {
            let obj = { level: 0 };
            for (let i = 1; i < 50; i++) {
                obj = { nested: obj, level: i };
            }
            const identity = (x) => x;
            const result = pipeline(obj, identity);
            expect(result).toEqual(obj);  // 541ns -> 500ns (8.20% faster)
        });

        test('should efficiently process multiple sequential string manipulations', () => {
            const functions = Array.from({ length: 50 }, (_, i) => (str) => str + i);
            const result = pipeline('start', ...functions);
            expect(result).toContain('start');  // 1.79μs -> 1.62μs (10.2% faster)
            expect(result.length).toBeGreaterThan('start'.length);
        });

        test('should handle 500 element array with multiple transformations', () => {
            const arr = Array.from({ length: 500 }, (_, i) => i);
            const multiply = (a) => a.map((x) => x * 2);
            const addOne = (a) => a.map((x) => x + 1);
            const result = pipeline(arr, multiply, addOne);
            expect(result).toHaveLength(500);  // 12.9μs -> 12.9μs (0.326% faster)
            expect(result[0]).toBe(1);
            expect(result[499]).toBe(999);
        });

        test('should handle pipeline with many object transformations', () => {
            const obj = { count: 0, data: [] };
            const functions = Array.from({ length: 50 }, (_, i) => (o) => ({
                ...o,
                count: o.count + 1,
                data: [...o.data, i]
            }));
            const result = pipeline(obj, ...functions);
            expect(result.count).toBe(50);  // 7.75μs -> 6.83μs (13.4% faster)
            expect(result.data).toHaveLength(50);
        });

        test('should handle pipeline with mixed type transformations efficiently', () => {
            const addNumber = (x) => x + 1;
            const toString = (x) => String(x);
            const addString = (x) => x + '_modified';
            const functions = [];
            for (let i = 0; i < 30; i++) {
                if (i % 3 === 0) functions.push(addNumber);
                else if (i % 3 === 1) functions.push(toString);
                else functions.push(addString);
            }
            const result = pipeline(10, ...functions);
            expect(typeof result).toBe('string');  // 3.67μs -> 3.42μs (7.32% faster)
        });
    });

});

To edit these changes git checkout codeflash/optimize-pipeline-mn6n1bxa and push.

Codeflash Static Badge

The optimization hoists `fns.length` out of the loop condition into a pre-computed constant (`const len`), eliminating redundant property lookups on every iteration. The original profiler data shows the loop condition consumed 46.7% of runtime, and after caching the length, that overhead drops to 4.5% while the actual function invocation (`result = fns[i](result)`) becomes the dominant cost at 82.7%—the expected hot-path. This single-line change yields a 7% speedup with no behavioral trade-offs, as confirmed by all regression tests passing with consistent or improved timings.
@codeflash-ai codeflash-ai bot requested a review from aseembits93 March 25, 2026 22:51
@codeflash-ai codeflash-ai bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash labels Mar 25, 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