The Computer Language
22.03 Benchmarks Game

reverse-complement TypeScript #7 program

source code

/*  The Computer Language Benchmarks Game
    https://salsa.debian.org/benchmarksgame-team/benchmarksgame/

    contributed by Joe Farro
    parts taken from solution contributed by
    Jos Hirth which was modified by 10iii
    modified by Roman Pletnev
    multi thread by Andrey Filatkin
*/

const { Worker, isMainThread, parentPort } = require('worker_threads');
const os = require('os');

const smap = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,84,86,71,72,0,
    0,67,68,0,0,77,0,75,78,0,0,0,89,83,65,65,66,87,0,82,
    0,0,0,0,0,0,0,84,86,71,72,0,0,67,68,0,0,77,0,75,78,0,
    0,0,89,83,65,65,66,87,0,82];

const lineLen = 60;
const fullLineLen = lineLen + 1;
const caret = '>'.charCodeAt(0);
const endLine = '\n'.charCodeAt(0);

if (isMainThread) {
    mainThread();
} else {
    workerThread();
}

async function mainThread() {
    let worker = null;
    let titleBuf = Buffer.allocUnsafe(lineLen);
    let titleBufPos = 0;
    let titleBufPartial = false;

    let dataArray = new SharedArrayBuffer(1 << 14);
    let dataBuf = Buffer.from(dataArray);
    let dataBufPos = 0;

    for await (let chunk of process.stdin) {
        await onChunk(chunk);
    }

    await onSection();
    await worker;

    async function onChunk(chunk) {
        const len = chunk.length;
        let i = 0;
        if (titleBufPartial) {
            const endI = chunk.indexOf(endLine, i);
            toTitleBuf(chunk, i, endI + 1);
            titleBufPartial = false;
            i += endI + 1;
        }
        const caretI = chunk.indexOf(caret, i);
        if (caretI === -1) {
            toBuf(chunk, i, len);
        } else {
            toBuf(chunk, i, caretI);
            i = caretI;
            await onSection();

            const endI = chunk.indexOf(endLine, i);
            if (endI !== -1) {
                toTitleBuf(chunk, i, endI + 1);
                return onChunk(chunk.subarray(endI + 1));
            } else {
                toTitleBuf(chunk, i, len);
                titleBufPartial = true;
            }
        }
    }

    function toTitleBuf(buffer, from, to) {
        buffer.copy(titleBuf, titleBufPos, from, to);
        titleBufPos += to - from;
    }

    function toBuf(buffer, from, to) {
        if (from === to) {
            return;
        }

        const len = to - from;
        while (dataBufPos + len > dataBuf.length) {
            const newArr = new SharedArrayBuffer(dataBuf.length * 2);
            const newBuf = Buffer.from(newArr);
            dataBuf.copy(newBuf, 0, 0, dataBufPos);
            dataArray = newArr;
            dataBuf = newBuf;
        }
        buffer.copy(dataBuf, dataBufPos, from, to);
        dataBufPos += len;
    }

    async function onSection() {
        if (titleBufPos === 0) {
            return;
        }

        await worker;

        worker = processData(titleBuf, titleBufPos, dataBuf, dataBufPos);

        titleBuf = Buffer.allocUnsafe(lineLen);
        titleBufPos = 0;
        titleBufPartial = false;

        dataArray = new SharedArrayBuffer(dataBuf.length);
        dataBuf = Buffer.from(dataArray);
        dataBufPos = 0;
    }

    function processData(titleBuf, titleBufLen, dataBuf, dataBufLen) {
        return new Promise(resolve => {
            const threads = Math.max(1, os.cpus().length - 2);
            const lines = Math.ceil(dataBufLen / fullLineLen);
            const dataLen = dataBufLen - lines;
            const chunkLen = Math.floor(dataLen / (2 * threads));

            let wait = 0;
            let bottomStart = 0;
            let bottomRealStart = 0;
            let topStart = dataLen;
            let topRealStart = topStart + Math.floor(topStart / lineLen);
            for (let i = 0; i < threads; i++) {
                const bottomFinish = i < threads - 1 ? bottomStart + chunkLen : dataLen >> 1;
                const topFinish = i < threads - 1 ? topStart - chunkLen : dataLen >> 1;
                const bottomRealFinish = bottomFinish + Math.floor(bottomFinish / lineLen);
                const topRealFinish = topFinish + Math.floor(topFinish / lineLen);

                const worker = new Worker(__filename);
                worker.postMessage({data: {
                    dataArray: dataBuf.buffer,
                    topFrom: topRealFinish,
                    bottomFrom: bottomRealStart,
                    topSize: topRealStart - topRealFinish,
                    bottomSize: bottomRealFinish - bottomRealStart
                }});
                worker.on('exit', () => {
                    wait--;
                    if (wait === 0) {
                        resolve();
                    }
                });
                wait++;

                bottomStart = bottomFinish;
                bottomRealStart = bottomRealFinish;
                topStart = topFinish;
                topRealStart = topRealFinish;
            }
        })
            .then(() => {
                process.stdout.write(titleBuf.subarray(0, titleBufLen));
                process.stdout.write(dataBuf.subarray(0, dataBufLen));
            });
    }
}

function workerThread() {
    parentPort.on('message', message => {
        writeBuf(message.data);
        process.exit();
    });

    function writeBuf({dataArray, topFrom, bottomFrom, topSize, bottomSize}) {
        const input = new Uint8Array(dataArray, topFrom, topSize);
        const output = new Uint8Array(dataArray, bottomFrom, bottomSize);

        let i = topSize - 1;
        let o = 0;
        while (i >= 0) {
            let char1 = input[i--];
            if (char1 === endLine) {
                char1 = input[i--];
            }
            let char2 = output[o++];
            if (char2 === endLine) {
                char2 = output[o++];
            }
            output[o - 1] = smap[char1];
            input[i + 1] = smap[char2];
        }
    }
}
    

notes, command-line, and program output

NOTES:
64-bit Ubuntu quad core
Version 4.6.2
node.js v17.8.0


Wed, 23 Mar 2022 21:29:40 GMT

MAKE:
mv revcomp.typescript-7.typescript revcomp.typescript-7.ts
/opt/src/node-v17.8.0/bin/tsc --target es2022 --strict --noEmitOnError --removeComments  revcomp.typescript-7.ts
revcomp.typescript-7.ts(11,9): error TS2451: Cannot redeclare block-scoped variable 'Worker'.
revcomp.typescript-7.ts(33,9): error TS7034: Variable 'worker' implicitly has type 'any' in some locations where its type cannot be determined.
revcomp.typescript-7.ts(49,20): error TS7023: 'onChunk' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
revcomp.typescript-7.ts(49,28): error TS7006: Parameter 'chunk' implicitly has an 'any' type.
revcomp.typescript-7.ts(77,25): error TS7006: Parameter 'buffer' implicitly has an 'any' type.
revcomp.typescript-7.ts(77,33): error TS7006: Parameter 'from' implicitly has an 'any' type.
revcomp.typescript-7.ts(77,39): error TS7006: Parameter 'to' implicitly has an 'any' type.
revcomp.typescript-7.ts(82,20): error TS7006: Parameter 'buffer' implicitly has an 'any' type.
revcomp.typescript-7.ts(82,28): error TS7006: Parameter 'from' implicitly has an 'any' type.
revcomp.typescript-7.ts(82,34): error TS7006: Parameter 'to' implicitly has an 'any' type.
revcomp.typescript-7.ts(104,15): error TS7005: Variable 'worker' implicitly has an 'any' type.
revcomp.typescript-7.ts(117,26): error TS7006: Parameter 'titleBuf' implicitly has an 'any' type.
revcomp.typescript-7.ts(117,36): error TS7006: Parameter 'titleBufLen' implicitly has an 'any' type.
revcomp.typescript-7.ts(117,49): error TS7006: Parameter 'dataBuf' implicitly has an 'any' type.
revcomp.typescript-7.ts(117,58): error TS7006: Parameter 'dataBufLen' implicitly has an 'any' type.
revcomp.typescript-7.ts(143,24): error TS2339: Property 'on' does not exist on type 'Worker'.
revcomp.typescript-7.ts(146,25): error TS2794: Expected 1 arguments, but got 0. Did you forget to include 'void' in your type argument to 'Promise'?
revcomp.typescript-7.ts(165,30): error TS7006: Parameter 'message' implicitly has an 'any' type.
revcomp.typescript-7.ts(170,24): error TS7031: Binding element 'dataArray' implicitly has an 'any' type.
revcomp.typescript-7.ts(170,35): error TS7031: Binding element 'topFrom' implicitly has an 'any' type.
revcomp.typescript-7.ts(170,44): error TS7031: Binding element 'bottomFrom' implicitly has an 'any' type.
revcomp.typescript-7.ts(170,56): error TS7031: Binding element 'topSize' implicitly has an 'any' type.
revcomp.typescript-7.ts(170,65): error TS7031: Binding element 'bottomSize' implicitly has an 'any' type.
../../../../../../opt/src/node-v17.8.0/lib/node_modules/typescript/lib/lib.dom.d.ts(16467,11): error TS2451: Cannot redeclare block-scoped variable 'Worker'.
../../../../../../opt/src/node-v17.8.0/lib/node_modules/typescript/lib/lib.dom.d.ts(16481,13): error TS2451: Cannot redeclare block-scoped variable 'Worker'.
make: [/home/dunham/all-benchmarksgame/2000-benchmarksgame/nanobench/makefiles/u64q.programs.Makefile:429: revcomp.typescript-7.typescript_run] Error 1 (ignored)

4.27s to complete and log all make actions

COMMAND LINE:
/opt/src/node-v17.8.0/bin/node --use_strict  revcomp.typescript-7.js 0 < revcomp-input250000.txt

PROGRAM FAILED 


PROGRAM OUTPUT:

node:internal/modules/cjs/loader:936
  throw err;
  ^

Error: Cannot find module '/home/dunham/all-benchmarksgame/benchmarksgame_i53330/revcomp/tmp/revcomp.typescript-7.js'
    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:933:15)
    at Function.Module._load (node:internal/modules/cjs/loader:778:27)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
    at node:internal/main/run_main_module:17:47 {
  code: 'MODULE_NOT_FOUND',
  requireStack: []
}

Node.js v17.8.0