Skip to content

Commit

Permalink
perf: Performance improvements.
Browse files Browse the repository at this point in the history
  • Loading branch information
miyaokamarina committed Nov 21, 2019
1 parent cc63ac2 commit 457d000
Show file tree
Hide file tree
Showing 11 changed files with 494 additions and 126 deletions.
150 changes: 77 additions & 73 deletions @ripreact/hsl-examples/src/benchmark.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,87 +2,91 @@ const { performance } = require('perf_hooks');
const { hsluvToHex } = require('hsluv');
const { hsl } = require('@ripreact/hsl/cjs');

const { min, max, round, random } = Math;

const normalize = n => round(max(0, min(n, 1)) * 255);

const old = (h, s, l) => {
let j;
let bottom;
let length;

const M = [
[3.240969941904521, -1.537383177570093, -0.498610760293],
[-0.96924363628087, 1.87596750150772, 0.041555057407175],
[0.055630079696993, -0.20397695888897, 1.056971514242878],
];

const fromLinear = c => (c <= 0.0031308 ? 12.92 * c : 1.055 * c ** 0.416666666666666685 - 0.055);

const { sin, cos, min } = Math;

const hrad = (h * Math.PI) / 180;
const bounds = [];
const sub1 = (l + 16) ** 3 / 1560896;
const sub2 = sub1 > 0.0088564516 ? sub1 : l / 903.2962962;

const _ = M.forEach(([a, b, c]) => {
for (j = 0; j < 2; j++) {
bottom = (632260 * c - 126452 * b) * sub2 + 126452 * j;

bounds.push([
((284517 * a - 94839 * c) * sub2) / bottom,
((838422 * c + 769860 * b + 731718 * a) * l * sub2 - 769860 * j * l) / bottom,
]);
}
});

const c = bounds.reduce((result, [a, b]) => {
length = b / (sin(hrad) - a * cos(hrad));

return length >= 0 ? min(result, (length / 100) * s) : result;
}, Infinity);

const varU = (cos(hrad) * c) / (13 * l) + 0.19783000664283;
const varV = (sin(hrad) * c) / (13 * l) + 0.46831999493879;

const y = l <= 8 ? l / 903.2962962 : ((l + 16) / 116) ** 3;
const x = -(9 * y * varU) / ((varU - 4) * varV - varU * varV);

return `rgba(${M.map(([a, b, c]) => {
return Math.round(
Math.max(0, min(fromLinear(a * x + b * y + (c * (9 * y - 15 * varV * y - varV * x)) / (3 * varV)), 1)) *
255,
);
})})`;
};
const { random } = Math;

// const old = (h, s, l) => {
// let j;
// let bottom;
// let length;
//
// const M = [
// [3.240969941904521, -1.537383177570093, -0.498610760293],
// [-0.96924363628087, 1.87596750150772, 0.041555057407175],
// [0.055630079696993, -0.20397695888897, 1.056971514242878],
// ];
//
// const fromLinear = c => (c <= 0.0031308 ? 12.92 * c : 1.055 * c ** 0.416666666666666685 - 0.055);
//
// const { sin, cos, min } = Math;
//
// const hrad = (h * Math.PI) / 180;
// const bounds = [];
// const sub1 = (l + 16) ** 3 / 1560896;
// const sub2 = sub1 > 0.0088564516 ? sub1 : l / 903.2962962;
//
// const _ = M.forEach(([a, b, c]) => {
// for (j = 0; j < 2; j++) {
// bottom = (632260 * c - 126452 * b) * sub2 + 126452 * j;
//
// bounds.push([
// ((284517 * a - 94839 * c) * sub2) / bottom,
// ((838422 * c + 769860 * b + 731718 * a) * l * sub2 - 769860 * j * l) / bottom,
// ]);
// }
// });
//
// const c = bounds.reduce((result, [a, b]) => {
// length = b / (sin(hrad) - a * cos(hrad));
//
// return length >= 0 ? min(result, (length / 100) * s) : result;
// }, Infinity);
//
// const varU = (cos(hrad) * c) / (13 * l) + 0.19783000664283;
// const varV = (sin(hrad) * c) / (13 * l) + 0.46831999493879;
//
// const y = l <= 8 ? l / 903.2962962 : ((l + 16) / 116) ** 3;
// const x = -(9 * y * varU) / ((varU - 4) * varV - varU * varV);
//
// return `rgba(${M.map(([a, b, c]) => {
// return Math.round(
// Math.max(0, min(fromLinear(a * x + b * y + (c * (9 * y - 15 * varV * y - varV * x)) / (3 * varV)), 1)) *
// 255,
// );
// })})`;
// };

const FunA = (h, s, l) => hsluvToHex([h, s, l]);
const FunB = (h, s, l) => hsl(h, s, l);
const FunC = (h, s, l) => old(h, s, l);
const FunB = hsl;
// const FunC = old;

let sum = [];
let acc = [];
let sum = 0;

for (let i = 0; i < 10000; i++) {
sum.push(FunB(random(), random(), random()));
sum.push(FunA(random(), random(), random()));
sum.push(FunC(random(), random(), random()));
acc.push(FunB(random(), random(), random()));
acc.push(FunA(random(), random(), random()));
// acc.push(FunC(random(), random(), random()));
}
sum = [];

const r = 1000000;
acc = [];

a = performance.now();
for (let i = 0; i < r; i++) sum.push(FunA(random(), random(), random()));
console.log('FunA : %s rps, side effect = %s.', (r / (performance.now() - a)) * 1000, sum.length);
sum = [];
const r = 3000000;

a = performance.now();
for (let i = 0; i < r; i++) sum.push(FunB(random(), random(), random()));
console.log('FunB : %s rps, side effect = %s.', (r / (performance.now() - a)) * 1000, sum.length);
sum = [];
for (let i = 0; i < r; i++) acc.push(FunB(random(), random(), random()));
sum += acc.length;
console.log('Latest : %s rps.', (r / (performance.now() - a)) * 1000);
acc = [];

a = performance.now();
for (let i = 0; i < r; i++) sum.push(FunC(random(), random(), random()));
console.log('FunC : %s rps, side effect = %s.', (r / (performance.now() - a)) * 1000, sum.length);
sum = [];
for (let i = 0; i < r; i++) acc.push(FunA(random(), random(), random()));
sum += acc.length;
console.log('Original : %s rps.', (r / (performance.now() - a)) * 1000);
acc = [];

// a = performance.now();
// for (let i = 0; i < r; i++) acc.push(FunC(random(), random(), random()));
// sum += acc.length;
// console.log('LINQ : %s rps.', (r / (performance.now() - a)) * 1000);
// acc = [];

global.sum = sum;
1 change: 0 additions & 1 deletion @ripreact/hsl/babel.config.cjs.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,4 @@ module.exports = {
],
'@babel/preset-typescript',
],
plugins: ['@babel/plugin-proposal-nullish-coalescing-operator'],
};
1 change: 0 additions & 1 deletion @ripreact/hsl/babel.config.esm.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,4 @@ module.exports = {
],
'@babel/preset-typescript',
],
plugins: ['@babel/plugin-proposal-nullish-coalescing-operator'],
};
4 changes: 2 additions & 2 deletions @ripreact/hsl/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
"devDependencies": {
"@babel/cli": "^7.7.0",
"@babel/core": "^7.7.2",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.4.4",
"@babel/preset-env": "^7.7.1",
"@babel/preset-typescript": "^7.7.2",
"typescript": "^3.7.2"
"typescript": "^3.7.2",
"wabt": "^1.0.12"
}
}
93 changes: 93 additions & 0 deletions @ripreact/hsl/src/index.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#include <math.h>;

#define M_PI 3.14159265358979323846

float M[9] = {
3.240969941904521,
-1.537383177570093,
-0.498610760293,

-0.96924363628087,
1.87596750150772,
0.041555057407175,

0.055630079696993,
-0.20397695888897,
1.056971514242878
};

float q = 126452;
float r = 769860;

static unsigned int normalize(float a) {
return fround(fmax(0, fmin(a, 1)) * 255);
}

/**
* Minimal and fast HSLᵤᵥ implementation. Returns `00rrggbb` int.
*
* @param h HSLᵤᵥ hue (0..360).
* @param s HSLᵤᵥ saturation (0..100).
* @param l HSLᵤᵥ lightness (0..100).
*/
unsigned int hsl(float h, float s, float l) {
h = (h * M_PI) / 180;

float hsin = sinf(h);
float hcos = cosf(h);

float t1 = l + 16;
float t2 = 13 * l;
float t3 = t1 / 116;

float sub1 = (t1 * t1 * t1) / 1560896;
float sub2 = sub1 > 0.0088564516 ? sub1 : l / 903.2962962;

unsigned int i;
float j;
float cmax = INFINITY;

float m1;
float m2;
float m3;

float bottom;
float length;

for (i = 0; i < 9; ) {
m1 = M[i++];
m2 = M[i++];
m3 = M[i++];

for (j = 0; j < 2; j++) {
bottom = (632260 * m3 - q * m2) * sub2 + q * j;

length =
((838422 * m3 + r * m2 + 731718 * m1) * l * sub2 - r * j * l) /
bottom /
(hsin - (((284517 * m1 - 94839 * m3) * sub2) / bottom) * hcos);

if (length >= 0) cmax = fmin(cmax, length);
}
}

float c = (cmax / 100) * s;

float varU = (hcos * c) / t2 + 0.19783000664283;
float varV = (hsin * c) / t2 + 0.46831999493879;

float y = l <= 8 ? l / 903.2962962 : t3 * t3 * t3;
float x = (-9 * y * varU) / ((varU - 4) * varV - varU * varV);
float z = (9 * y - 15 * varV * y - varV * x) / (3 * varV);

unsigned int dot = M[0] * x + M[1] * y + M[2] * z;
unsigned int rgb = normalize(dot <= 0.0031308 ? 12.92 * dot : 1.055 * powf(dot, 0.416666666666666685) - 0.055) << 16;

dot = M[3] * x + M[4] * y + M[5] * z;
rgb |= normalize(dot <= 0.0031308 ? 12.92 * dot : 1.055 * powf(dot, 0.416666666666666685) - 0.055) << 8;

dot = M[6] * x + M[7] * y + M[8] * z;
rgb |= normalize(dot <= 0.0031308 ? 12.92 * dot : 1.055 * powf(dot, 0.416666666666666685) - 0.055);

return rgb;
};
75 changes: 44 additions & 31 deletions @ripreact/hsl/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,52 +33,65 @@ const hex = (x: number, w: number) => {
* @param l HSLᵤᵥ lightness (0..100).
*/
export const hsl = (h: number, s: number, l: number) => {
let p = l + 16;
let i = p ** 3 / 1560896; // ← `sub1`
h = (h * Math.PI) / 180;

let hsin = Math.sin(h);
let hcos = Math.cos(h);

const t1 = l + 16;
const t2 = 13 * l;
const t3 = t1 / 116;

const sub1 = (t1 * t1 * t1) / 1560896;
const sub2 = sub1 > 0.0088564516 ? sub1 : l / 903.2962962;

let i: number;
let j: number;
let x: number;
let y: number;
let z: number;
let m = i > 0.0088564516 ? i : l / 903.2962962; // ← `sub2`
let n: number;
let o = Infinity; // ← `c`
let cmax = Infinity;

h = (h * Math.PI) / 180; // ← `hrad`
let m1: number;
let m2: number;
let m3: number;

let bottom: number;
let length: number;

for (i = 0; i < 9; ) {
x = M[i++];
y = M[i++];
z = M[i++];
m1 = M[i++];
m2 = M[i++];
m3 = M[i++];

for (j = 0; j < 2; j++) {
n = (632260 * z - q * y) * m + q * j; // ← `bottom`
bottom = (632260 * m3 - q * m2) * sub2 + q * j;

// `length` ↓
n =
((838422 * z + r * y + 731718 * x) * l * m - r * j * l) /
n /
(Math.sin(h) - (((284517 * x - 94839 * z) * m) / n) * Math.cos(h));
length =
((838422 * m3 + r * m2 + 731718 * m1) * l * sub2 - r * j * l) /
bottom /
(hsin - (((284517 * m1 - 94839 * m3) * sub2) / bottom) * hcos);

o = n >= 0 ? Math.min(o, (n / 100) * s) : o; // ← `c`
if (length >= 0) cmax = Math.min(cmax, length);
}
}

i = l * 13;
m = (Math.cos(h) * o) / i + 0.19783000664283; // ← `varU`
n = (Math.sin(h) * o) / i + 0.46831999493879; // ← `varV`
const c = (cmax / 100) * s;

l = l <= 8 ? l / 903.2962962 : (p / 116) ** 3; // ← `y`
m = -(9 * l * m) / ((m - 4) * n - m * n); // ← `x`
n = (9 * l - 15 * n * l - n * m) / (3 * n);
o = 0; // ← `rgb`
const varU = (hcos * c) / t2 + 0.19783000664283;
const varV = (hsin * c) / t2 + 0.46831999493879;

for (i = 0, j = 16; i < 9; j -= 8) {
p = M[i++] * m + M[i++] * l + M[i++] * n;
const y = l <= 8 ? l / 903.2962962 : t3 * t3 * t3;
const x = (-9 * y * varU) / ((varU - 4) * varV - varU * varV);
const z = (9 * y - 15 * varV * y - varV * x) / (3 * varV);

o += (normalize(p <= 0.0031308 ? 12.92 * p : 1.055 * p ** 0.416666666666666685 - 0.055) << j) >>> 0;
}
let dot = M[0] * x + M[1] * y + M[2] * z;
let rgb = normalize(dot <= 0.0031308 ? 12.92 * dot : 1.055 * dot ** 0.416666666666666685 - 0.055) << 16;

dot = M[3] * x + M[4] * y + M[5] * z;
rgb |= normalize(dot <= 0.0031308 ? 12.92 * dot : 1.055 * dot ** 0.416666666666666685 - 0.055) << 8;

dot = M[6] * x + M[7] * y + M[8] * z;
rgb |= normalize(dot <= 0.0031308 ? 12.92 * dot : 1.055 * dot ** 0.416666666666666685 - 0.055);

return '#' + hex(o, 6);
return '#' + hex(rgb, 6);
};

/**
Expand Down
Loading

0 comments on commit 457d000

Please sign in to comment.