build(deps-dev): apply updates
[poolifier.git] / benchmarks / worker-selection / least.mjs
... / ...
CommitLineData
1import { randomInt } from 'node:crypto'
2
3import { bench, group, run } from 'tatami-ng'
4
5/**
6 *
7 * @param numberOfWorkers
8 * @param maxNumberOfTasksPerWorker
9 * @returns
10 */
11function generateRandomTasksMap (
12 numberOfWorkers,
13 maxNumberOfTasksPerWorker = 10
14) {
15 const tasksArray = []
16 for (let i = 0; i < numberOfWorkers; i++) {
17 const task = [i, randomInt(maxNumberOfTasksPerWorker)]
18 tasksArray.push(task)
19 }
20 return new Map(tasksArray)
21}
22
23const tasksMap = generateRandomTasksMap(60, 20)
24
25/**
26 *
27 * @param tasksMap
28 * @returns
29 */
30function loopSelect (tasksMap) {
31 let minKey
32 let minValue = Number.POSITIVE_INFINITY
33 for (const [key, value] of tasksMap) {
34 if (value === 0) {
35 return key
36 } else if (value < minValue) {
37 minKey = key
38 minValue = value
39 }
40 }
41 return [minKey, minValue]
42}
43
44/**
45 *
46 * @param tasksMap
47 * @returns
48 */
49function arraySortSelect (tasksMap) {
50 const tasksArray = Array.from(tasksMap)
51 return tasksArray.sort((a, b) => {
52 if (a[1] < b[1]) {
53 return -1
54 } else if (a[1] > b[1]) {
55 return 1
56 }
57 return 0
58 })[0]
59}
60
61const defaultComparator = (a, b) => {
62 return a < b
63}
64
65const defaultPivotIndexSelect = (leftIndex, rightIndex) => {
66 return leftIndex + Math.floor((rightIndex - leftIndex) / 2)
67}
68
69const randomPivotIndexSelect = (leftIndex, rightIndex) => {
70 return randomInt(leftIndex, rightIndex)
71}
72
73/**
74 *
75 * @param array
76 * @param index1
77 * @param index2
78 */
79function swap (array, index1, index2) {
80 const tmp = array[index1]
81 array[index1] = array[index2]
82 array[index2] = tmp
83}
84
85/**
86 *
87 * @param array
88 * @param leftIndex
89 * @param rightIndex
90 * @param pivotIndex
91 * @param compare
92 * @returns
93 */
94function partition (
95 array,
96 leftIndex,
97 rightIndex,
98 pivotIndex,
99 compare = defaultComparator
100) {
101 const pivotValue = array[pivotIndex]
102 swap(array, pivotIndex, rightIndex)
103 let storeIndex = leftIndex
104 for (let i = leftIndex; i < rightIndex; i++) {
105 if (compare(array[i], pivotValue)) {
106 swap(array, storeIndex, i)
107 storeIndex++
108 }
109 }
110 swap(array, rightIndex, storeIndex)
111 return storeIndex
112}
113
114/**
115 *
116 * @param array
117 * @param k
118 * @param leftIndex
119 * @param rightIndex
120 * @param compare
121 * @param pivotIndexSelect
122 * @returns
123 */
124function selectLoop (
125 array,
126 k,
127 leftIndex,
128 rightIndex,
129 compare = defaultComparator,
130 pivotIndexSelect = defaultPivotIndexSelect
131) {
132 while (true) {
133 if (leftIndex === rightIndex) return array[leftIndex]
134 let pivotIndex = pivotIndexSelect(leftIndex, rightIndex)
135 pivotIndex = partition(array, leftIndex, rightIndex, pivotIndex, compare)
136 if (k === pivotIndex) {
137 return array[k]
138 } else if (k < pivotIndex) {
139 rightIndex = pivotIndex - 1
140 } else {
141 leftIndex = pivotIndex + 1
142 }
143 }
144}
145
146/**
147 *
148 * @param array
149 * @param k
150 * @param leftIndex
151 * @param rightIndex
152 * @param compare
153 * @param pivotIndexSelect
154 * @returns
155 */
156function selectRecursion (
157 array,
158 k,
159 leftIndex,
160 rightIndex,
161 compare = defaultComparator,
162 pivotIndexSelect = defaultPivotIndexSelect
163) {
164 if (leftIndex === rightIndex) return array[leftIndex]
165 let pivotIndex = pivotIndexSelect(leftIndex, rightIndex)
166 pivotIndex = partition(array, leftIndex, rightIndex, pivotIndex, compare)
167 if (k === pivotIndex) {
168 return array[k]
169 } else if (k < pivotIndex) {
170 return selectRecursion(array, k, leftIndex, pivotIndex - 1, compare)
171 } else {
172 return selectRecursion(array, k, pivotIndex + 1, rightIndex, k, compare)
173 }
174}
175
176/**
177 *
178 * @param tasksMap
179 * @returns
180 */
181function quickSelectLoop (tasksMap) {
182 const tasksArray = Array.from(tasksMap)
183
184 return selectLoop(tasksArray, 0, 0, tasksArray.length - 1, (a, b) => {
185 return a[1] < b[1]
186 })
187}
188
189/**
190 *
191 * @param tasksMap
192 * @returns
193 */
194function quickSelectLoopRandomPivot (tasksMap) {
195 const tasksArray = Array.from(tasksMap)
196
197 return selectLoop(
198 tasksArray,
199 0,
200 0,
201 tasksArray.length - 1,
202 (a, b) => {
203 return a[1] < b[1]
204 },
205 randomPivotIndexSelect
206 )
207}
208
209/**
210 *
211 * @param tasksMap
212 * @returns
213 */
214function quickSelectRecursion (tasksMap) {
215 const tasksArray = Array.from(tasksMap)
216
217 return selectRecursion(tasksArray, 0, 0, tasksArray.length - 1, (a, b) => {
218 return a[1] < b[1]
219 })
220}
221
222/**
223 *
224 * @param tasksMap
225 * @returns
226 */
227function quickSelectRecursionRandomPivot (tasksMap) {
228 const tasksArray = Array.from(tasksMap)
229
230 return selectRecursion(
231 tasksArray,
232 0,
233 0,
234 tasksArray.length - 1,
235 (a, b) => {
236 return a[1] < b[1]
237 },
238 randomPivotIndexSelect
239 )
240}
241
242group('Least used worker tasks distribution', () => {
243 bench('Loop select', () => {
244 loopSelect(tasksMap)
245 })
246 bench('Array sort select', () => {
247 arraySortSelect(tasksMap)
248 })
249 bench('Quick select loop', () => {
250 quickSelectLoop(tasksMap)
251 })
252 bench('Quick select loop with random pivot', () => {
253 quickSelectLoopRandomPivot(tasksMap)
254 })
255 bench('Quick select recursion', () => {
256 quickSelectRecursion(tasksMap)
257 })
258 bench('Quick select recursion with random pivot', () => {
259 quickSelectRecursionRandomPivot(tasksMap)
260 })
261})
262
263await run({ units: true })