markers-average.ts 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. import * as B from 'benchmark';
  2. function uint8ForLoop(array: Uint8Array, count: number): number {
  3. if (count === 0) return 0;
  4. let sum = 0;
  5. for (let i = 0; i < count; ++i) {
  6. sum += array[i] && 1;
  7. }
  8. return sum / count;
  9. }
  10. function uint32ForLoop(array: Uint8Array, count: number): number {
  11. if (count === 0) return 0;
  12. const view = new Uint32Array(array.buffer, 0, array.buffer.byteLength >> 2);
  13. const viewEnd = (count - 4) >> 2;
  14. const backStart = 4 * viewEnd;
  15. let sum = 0;
  16. for (let i = 0; i < viewEnd; ++i) {
  17. const v = view[i];
  18. sum += ((v & 0xFF) && 1) + ((v & 0xFF00) && 1) + ((v & 0xFF0000) && 1) + ((v & 0xFF000000) && 1);
  19. }
  20. for (let i = backStart; i < count; ++i) {
  21. sum += array[i] && 1;
  22. }
  23. return sum / count;
  24. }
  25. function uint32ForLoopAddOnlyBaseline(array: Uint8Array, count: number): number {
  26. if (count === 0) return 0;
  27. const view = new Uint32Array(array.buffer, 0, array.buffer.byteLength >> 2);
  28. const viewEnd = (count - 4) >> 2;
  29. const backStart = 4 * viewEnd;
  30. let sum = 0;
  31. for (let i = 0; i < viewEnd; ++i) {
  32. const v = view[i];
  33. sum += v;
  34. }
  35. for (let i = backStart; i < count; ++i) {
  36. sum += array[i] && 1;
  37. }
  38. return sum / count;
  39. }
  40. function createTypedLut() {
  41. const lut = new Uint8Array(0x0303 + 1);
  42. lut[0x0001] = 1;
  43. lut[0x0002] = 1;
  44. lut[0x0003] = 1;
  45. lut[0x0100] = 1;
  46. lut[0x0200] = 1;
  47. lut[0x0300] = 1;
  48. lut[0x0101] = 2;
  49. lut[0x0201] = 2;
  50. lut[0x0301] = 2;
  51. lut[0x0102] = 2;
  52. lut[0x0202] = 2;
  53. lut[0x0302] = 2;
  54. lut[0x0103] = 2;
  55. lut[0x0203] = 2;
  56. lut[0x0303] = 2;
  57. return lut;
  58. }
  59. function createNativeLut() {
  60. const lut: number[] = [];
  61. for (let i = 0, il = 0x0303 + 1; i < il; ++i) lut[i] = 0;
  62. lut[0x0000] = 0;
  63. lut[0x0001] = 1;
  64. lut[0x0002] = 1;
  65. lut[0x0003] = 1;
  66. lut[0x0100] = 1;
  67. lut[0x0200] = 1;
  68. lut[0x0300] = 1;
  69. lut[0x0101] = 2;
  70. lut[0x0201] = 2;
  71. lut[0x0301] = 2;
  72. lut[0x0102] = 2;
  73. lut[0x0202] = 2;
  74. lut[0x0302] = 2;
  75. lut[0x0103] = 2;
  76. lut[0x0203] = 2;
  77. lut[0x0303] = 2;
  78. return lut;
  79. }
  80. function createTypedLut2bits() {
  81. const lut = new Uint8Array(256);
  82. for (let a = 0; a < 4; ++a) {
  83. for (let b = 0; b < 4; ++b) {
  84. for (let c = 0; c < 4; ++c) {
  85. for (let d = 0; d < 4; ++d) {
  86. const i = d | c << 2 | b << 4 | a << 6;
  87. const v = (a && 1) + (b && 1) + (c && 1) + (d && 1);
  88. lut[i] = v;
  89. // console.log([a, b, c, d], i, v);
  90. }
  91. }
  92. }
  93. }
  94. return lut;
  95. }
  96. const lutNative = createNativeLut();
  97. const lutTyped = createTypedLut();
  98. const lutTyped2bits = createTypedLut2bits();
  99. function uint32ForLoopWithLutNative(array: Uint8Array, count: number): number {
  100. if (count === 0) return 0;
  101. const view = new Uint32Array(array.buffer, 0, array.buffer.byteLength >> 2);
  102. const viewEnd = (count - 4) >> 2;
  103. const backStart = 4 * viewEnd;
  104. let sum = 0;
  105. for (let i = 0; i < viewEnd; ++i) {
  106. const v = view[i];
  107. sum += lutNative[v & 0xFFFF] + lutNative[v >> 16];
  108. }
  109. for (let i = backStart; i < count; ++i) {
  110. sum += array[i] && 1;
  111. }
  112. return sum / count;
  113. }
  114. function uint32ForLoopWithLutTyped(array: Uint8Array, count: number): number {
  115. if (count === 0) return 0;
  116. const view = new Uint32Array(array.buffer, 0, array.buffer.byteLength >> 2);
  117. const viewEnd = (count - 4) >> 2;
  118. const backStart = 4 * viewEnd;
  119. let sum = 0;
  120. for (let i = 0; i < viewEnd; ++i) {
  121. const v = view[i];
  122. sum += lutTyped[v & 0xFFFF] + lutTyped[v >> 16];
  123. }
  124. for (let i = backStart; i < count; ++i) {
  125. sum += array[i] && 1;
  126. }
  127. return sum / count;
  128. }
  129. function uint32ForLoopWithLut2bits(array: Uint8Array, count: number): number {
  130. if (count === 0) return 0;
  131. const view = new Uint32Array(array.buffer, 0, array.buffer.byteLength >> 2);
  132. const viewEnd = (count - 4) >> 2;
  133. const backStart = 4 * viewEnd;
  134. let sum = 0;
  135. for (let i = 0; i < viewEnd; ++i) {
  136. const v = view[i];
  137. sum += lutTyped2bits[(v >> 18 | v >> 12 | v >> 6 | v) & 0xFF];
  138. }
  139. for (let i = backStart; i < count; ++i) {
  140. sum += array[i] && 1;
  141. }
  142. return sum / count;
  143. }
  144. function createData(elements: number, instances: number) {
  145. const data = new Uint8Array(4000 * 5000);
  146. const start = Math.floor(instances / 2);
  147. data.fill(1, start, start + elements);
  148. return data;
  149. };
  150. export function run(elements: number, instances: number) {
  151. const suite = new B.Suite();
  152. const count = elements * instances;
  153. const data = createData(elements, instances);
  154. console.log('uint8ForLoop', uint8ForLoop(data, count));
  155. console.log('uint32ForLoop', uint32ForLoop(data, count));
  156. console.log('uint32ForLoopWithLutNative', uint32ForLoopWithLutNative(data, count));
  157. console.log('uint32ForLoopWithLutTyped', uint32ForLoopWithLutTyped(data, count));
  158. console.log('uint32ForLoopWithLut2bits', uint32ForLoopWithLut2bits(data, count));
  159. suite
  160. .add('uint8ForLoop', () => uint8ForLoop(data, count))
  161. .add('uint32ForLoop', () => uint32ForLoop(data, count))
  162. .add('uint32ForLoopAddOnlyBaseline', () => uint32ForLoopAddOnlyBaseline(data, count))
  163. .add('uint32ForLoopWithLutNative', () => uint32ForLoopWithLutNative(data, count))
  164. .add('uint32ForLoopWithLutTyped', () => uint32ForLoopWithLutTyped(data, count))
  165. .add('uint32ForLoopWithLut2bits', () => uint32ForLoopWithLut2bits(data, count))
  166. .on('cycle', (e: any) => console.log(String(e.target)))
  167. .run();
  168. }
  169. // console.log(createTypedLut2bits());
  170. // run(5000, 4000);
  171. // uint8ForLoop 0.00025
  172. // uint32ForLoop 0.00025
  173. // uint32ForLoopWithLutNative 0.00025
  174. // uint32ForLoopWithLutTyped 0.00025
  175. // uint32ForLoopWithLut2bits 0.00025
  176. // uint8ForLoop x 49.84 ops/sec ±3.30% (64 runs sampled)
  177. // uint32ForLoop x 97.70 ops/sec ±1.71% (71 runs sampled)
  178. // uint32ForLoopAddOnlyBaseline x 220 ops/sec ±2.49% (85 runs sampled)
  179. // uint32ForLoopWithLutNative x 135 ops/sec ±1.71% (76 runs sampled)
  180. // uint32ForLoopWithLutTyped x 137 ops/sec ±1.69% (77 runs sampled)
  181. // uint32ForLoopWithLut2bits x 111 ops/sec ±2.73% (70 runs sampled)