diff --git a/javascript/optimize-nohup.sh b/javascript/optimize-nohup.sh index fb4b88ab..c4064cdd 100644 --- a/javascript/optimize-nohup.sh +++ b/javascript/optimize-nohup.sh @@ -1,4 +1,4 @@ #!/bin/bash set -e -nohup npm run optimize-bdd > optimize.nohup.out & +nohup npm run optimize-parallel > optimize.nohup.out & diff --git a/javascript/package.json b/javascript/package.json index b91d4fb6..b724e26e 100644 --- a/javascript/package.json +++ b/javascript/package.json @@ -58,7 +58,16 @@ "iterative-fuzzing:5": "npm run iterative-fuzzing", "iterative-fuzzing:6": "npm run iterative-fuzzing", "iterative-fuzzing:7": "npm run iterative-fuzzing", - "iterative-fuzzing:8": "npm run iterative-fuzzing" + "iterative-fuzzing:8": "npm run iterative-fuzzing", + "optimize-parallel": "npm-run-all --parallel optimize:*", + "optimize:1": "npm run optimize-bdd", + "optimize:2": "npm run optimize-bdd", + "optimize:3": "npm run optimize-bdd", + "optimize:4": "npm run optimize-bdd", + "optimize:5": "npm run optimize-bdd", + "optimize:6": "npm run optimize-bdd", + "optimize:7": "npm run optimize-bdd", + "optimize:8": "npm run optimize-bdd" }, "author": "pubkey", "devDependencies": { @@ -83,6 +92,6 @@ }, "dependencies": { "array-push-at-sort-position": "4.0.1", - "binary-decision-diagram": "3.1.0" + "binary-decision-diagram": "3.2.0" } } diff --git a/javascript/src/actions/action-functions.ts b/javascript/src/actions/action-functions.ts index 1fb57b82..06deb19f 100644 --- a/javascript/src/actions/action-functions.ts +++ b/javascript/src/actions/action-functions.ts @@ -75,7 +75,6 @@ export const removeExisting: ActionFunction = (input) => { for (let i = 0; i < results.length; i++) { const item = results[i]; // remove - // console.dir(item); if (item[primary] === input.changeEvent.id) { results.splice(i, 1); break; diff --git a/javascript/src/bdd/bdd.generated.ts b/javascript/src/bdd/bdd.generated.ts index b4c2e430..d3e2c90c 100644 --- a/javascript/src/bdd/bdd.generated.ts +++ b/javascript/src/bdd/bdd.generated.ts @@ -3,11 +3,10 @@ import { minimalStringToSimpleBdd, resolveWithSimpleBdd } from 'binary-decision-diagram'; - import type { StateResolveFunctionInput } from '../types/index.js'; import { stateResolveFunctionByIndex } from '../states/index.js'; -export const minimalBddString = '14a1b,c+d2e5f0g/h.i4j*k-l)m(n6obh9pce9qnh9rad9scm9tae9uan9vbf9wbe9xbn9ycg9zck9{cn9|nd9}ne9~nf9ng9¡nm9¢nk9£mh9¤mi9¥mj9¦mk9§ml9¨mn9©£¦,ªmc8«¤{8¬¥z8­¨s8®¨n8¯mn8°¨¡8±¨m8²mª4³£©4´¤«4µ¥¬4¶¨­4·¨®4¸m¯4¹¨°4ºpz7»´µ7¼{z7½·¸7¾}n7¿¤¥7À¨m7Á¤§6Âwo6ä­6Ä»¶6Åtu6Æwx6Ǩ©6ÈÀ³6ɾ}6Ênq6˨°6̽¹6;n6ο§6Ï¿¨6ÐÀ©6ÑÀ¨6Òac0Óbc0Ôtº0ÕÂz0Öry0׿0Øvz0ÙÆ{0Úɾ0ÛÊn0Ü|0ÝÍn0Þ~¢0ß²m5à¸m5áÁ¥5âÃ¥5ãÄÏ5äÇm5åÈÐ5æËm5çÌÑ5èáÎ2éÖÔ2êØÕ2ëâã2ìÖ×2íØÙ2îäå2ïÜÚ2ðÞÛ2ñæç2òÜÝ2óÞn2ôßà/õÒn/öÓn/÷èî/øéï/ùêð/úëñ/ûìò/üíó/ýÎÐ/þÏÑ/ÿmô-Ā÷ú-āøû-Ăùü-㧱-Ąýþ-ą§¨-Ćõö1ćāĂ1ĈĀÿ*ĉćĆ*Ċăm*ċĈĉ3ČċĊ.襹.Čč('; +export const minimalBddString = '14a1b,c+d2e5f0g/h.i4j*k-l)m(n6obh9pce9qnh9rad9scm9tae9uan9vbf9wbe9xbn9ycg9zck9{cn9|nd9}ne9~nf9ng9¡nm9¢nk9£mh9¤mi9¥mj9¦mk9§ml9¨mn9©mc8ª¤{8«¥z8¬¨s8­¨n8®mn8¯¨¡8°¨m8±pz7²ª«7³{z7´­®7µ}n7¶¤¥7·¨m7¸wo6¹µ}6ºnq6»²¬6¼tu6½wx6¾´¯6¿µn6À®¯6Á¶§6·£6ö¨6Ä·¨6Åm¦6Æm¨6Ǥ¥5Ȩm5Ém©4Êm®4Ëǧ4ÌÈ£4ÍǬ4Îû4Ïȯ4Ðľ4Ñm¦4Òm¯4ÓÆÀ4Ôma3Õmn3ÖÉa3×Ên3ØËr3ÙÁt3ÚÌ|3Û¹3ÜÍr3Ýμ3ÞÏ|3ßп3àØÙ2áv¸2ây±2ãÚÛ2ä~º2åµ2æÜÝ2çv½2èy³2éz{2êÞß2ë~n2ìn2íÑÅ2îÒÓ2ï¢n2ðÔb1ñÕn1òÖb1ó×n1ôàá1õâz1öãä1÷æç1øèé1ùêë1úðc0ûñn0üòc0ýón0þmn0ÿÊn0Āôõ0āöå0Ă÷ø0ăùì0Ąíï0ąîï0Ćúû/ćüý/ĈĀā/ĉĂă/ĊÁÂ/ċÃÄ/Čúm.čüm.ĎĆm.ďćm.Đþm.đÿm.ĒĀ§.ēĂ°.ĔĈ§.ĕĉ°.ĖĄ§.ėą°.ĘÁ§.ęè.ĚĊ§.ěċ¨.Ĝŧ.ĝƨ.ĞČč-ğĎď-ĠĐđ-ġĒē-ĢĔĕ-ģĖė-ĤĘę-ĥĚě-ĦĜĝ-ħğĠ,ĨĢģ,ĩĥĦ,ĪĞħ+īġĨ+ĬĤĩ+ĭĪī)ĭĬ('; let simpleBdd: SimpleBdd | undefined; export function getSimpleBdd() { diff --git a/javascript/src/bdd/bdd.optimize.state.json b/javascript/src/bdd/bdd.optimize.state.json new file mode 100644 index 00000000..1136c920 --- /dev/null +++ b/javascript/src/bdd/bdd.optimize.state.json @@ -0,0 +1,24 @@ +{ + "performanceMeasurement": { + "isInsert": 0.0005134089980274439, + "isUpdate": 0.0005059200078248977, + "isDelete": 0.0005452740341424942, + "hasLimit": 0.0004327639751136303, + "isFindOne": 0.00046740003488957883, + "hasSkip": 0.0004786954801529646, + "wasResultsEmpty": 0.00046854151226580145, + "wasLimitReached": 0.0005687805358320474, + "wasFirst": 0.0006331859696656466, + "wasLast": 0.000993298990651965, + "sortParamsChanged": 0.0021037884596735237, + "wasInResult": 0.001067824000492692, + "wasSortedBeforeFirst": 0.005706427520141006, + "wasSortedAfterLast": 0.0063148145023733376, + "isSortedBeforeFirst": 0.005680875465273857, + "isSortedAfterLast": 0.006254887519404292, + "wasMatching": 0.02021647496894002, + "doesMatchNow": 0.016383298518136143 + }, + "minimalBddString": "14a1b,c+d2e5f0g/h.i4j*k-l)m(n6obh9pce9qnh9rad9scm9tae9uan9vbf9wbe9xbn9ycg9zck9{cn9|nd9}ne9~nf9ng9¡nm9¢nk9£mh9¤mi9¥mj9¦mk9§ml9¨mn9©mc8ª¤{8«¥z8¬¨s8­¨n8®mn8¯¨¡8°¨m8±pz7²ª«7³{z7´­®7µ}n7¶¤¥7·¨m7¸wo6¹µ}6ºnq6»²¬6¼tu6½wx6¾´¯6¿µn6À®¯6Á¶§6·£6ö¨6Ä·¨6Åm¦6Æm¨6Ǥ¥5Ȩm5Ém©4Êm®4Ëǧ4ÌÈ£4ÍǬ4Îû4Ïȯ4Ðľ4Ñm¦4Òm¯4ÓÆÀ4Ôma3Õmn3ÖÉa3×Ên3ØËr3ÙÁt3ÚÌ|3Û¹3ÜÍr3Ýμ3ÞÏ|3ßп3àØÙ2áv¸2ây±2ãÚÛ2ä~º2åµ2æÜÝ2çv½2èy³2éz{2êÞß2ë~n2ìn2íÑÅ2îÒÓ2ï¢n2ðÔb1ñÕn1òÖb1ó×n1ôàá1õâz1öãä1÷æç1øèé1ùêë1úðc0ûñn0üòc0ýón0þmn0ÿÊn0Āôõ0āöå0Ă÷ø0ăùì0Ąíï0ąîï0Ćúû/ćüý/ĈĀā/ĉĂă/ĊÁÂ/ċÃÄ/Čúm.čüm.ĎĆm.ďćm.Đþm.đÿm.ĒĀ§.ēĂ°.ĔĈ§.ĕĉ°.ĖĄ§.ėą°.ĘÁ§.ęè.ĚĊ§.ěċ¨.Ĝŧ.ĝƨ.ĞČč-ğĎď-ĠĐđ-ġĒē-ĢĔĕ-ģĖė-ĤĘę-ĥĚě-ĦĜĝ-ħğĠ,ĨĢģ,ĩĥĦ,ĪĞħ+īġĨ+ĬĤĩ+ĭĪī)ĭĬ(", + "quality": 587.3026994052454 +} \ No newline at end of file diff --git a/javascript/src/bdd/bdd.template.ts b/javascript/src/bdd/bdd.template.ts index eb0d6a07..55a2736c 100644 --- a/javascript/src/bdd/bdd.template.ts +++ b/javascript/src/bdd/bdd.template.ts @@ -3,7 +3,6 @@ import { minimalStringToSimpleBdd, resolveWithSimpleBdd } from 'binary-decision-diagram'; - import type { StateResolveFunctionInput } from '../types/index.js'; import { stateResolveFunctionByIndex } from '../states/index.js'; diff --git a/javascript/src/bdd/write-bdd-template.ts b/javascript/src/bdd/write-bdd-template.ts index 41c2e02e..e76ee2bb 100644 --- a/javascript/src/bdd/write-bdd-template.ts +++ b/javascript/src/bdd/write-bdd-template.ts @@ -1,17 +1,26 @@ import * as fs from 'fs'; import path from 'path'; +import { + PerformanceMeasurement +} from '../truth-table-generator/calculate-bdd-quality.js'; export const BDD_TEMPLATE_LOCATION = path.join( __dirname, './bdd.template.ts' ); +export const BDD_OPTIMIZE_STATE_LOCATION = path.join( + __dirname, + './bdd.optimize.state.json' +); export const BDD_TEMPLATE_GOAL = path.join( __dirname, './bdd.generated.ts' ); export function writeBddTemplate( - minimalBddString: string + minimalBddString: string, + performanceMeasurement: PerformanceMeasurement, + quality: number ) { let templateString: string = fs.readFileSync(BDD_TEMPLATE_LOCATION, 'utf-8'); const replaceVariables = { @@ -24,6 +33,17 @@ export function writeBddTemplate( templateString = templateString.replace(templateVar, contentString); }); + fs.writeFileSync( + BDD_OPTIMIZE_STATE_LOCATION, + JSON.stringify({ + performanceMeasurement, + minimalBddString, + quality + }, null, 4), + { encoding: 'utf8', flag: 'w' } + ); + + fs.writeFileSync( BDD_TEMPLATE_GOAL, templateString, diff --git a/javascript/src/truth-table-generator/calculate-bdd-quality.ts b/javascript/src/truth-table-generator/calculate-bdd-quality.ts index c0975315..884c9b3f 100644 --- a/javascript/src/truth-table-generator/calculate-bdd-quality.ts +++ b/javascript/src/truth-table-generator/calculate-bdd-quality.ts @@ -4,7 +4,7 @@ import { ResolverFunctions } from 'binary-decision-diagram'; import { - performanceNow + performanceNow, wait } from 'async-test-util'; import type { @@ -133,11 +133,15 @@ export async function measurePerformanceOfStateFunctions( const diff = endTime - startTime; ret[stateName] = ret[stateName] + diff; } + + if (remainingRounds % 10 === 0) { + console.log('.. ' + remainingRounds); + await wait(50); + } } // calculate average orderedStateList.forEach(k => ret[k] = (ret[k] / rounds)); - return ret; } @@ -166,6 +170,8 @@ export async function getBetterBdd( } } + + export type FunctionUsageCount = { [k in StateName]: number; }; diff --git a/javascript/src/truth-table-generator/index.ts b/javascript/src/truth-table-generator/index.ts index 012ee8e3..96a49bcc 100644 --- a/javascript/src/truth-table-generator/index.ts +++ b/javascript/src/truth-table-generator/index.ts @@ -182,19 +182,12 @@ export function doesActionWork( return true; } - /* - console.log('--- '.repeat(100)); - console.dir(input); - console.dir(input.previousResults); - console.dir(resultAfter);*/ - const calculatedResults = runAction( actionName, input.queryParams, input.changeEvent, input.previousResults.slice() ); - // console.dir(calculatedResults); if ( // optimisation shortcut, this is faster because we know we have two arrays diff --git a/javascript/src/truth-table-generator/runner.node.ts b/javascript/src/truth-table-generator/runner.node.ts index 91450e67..18c34086 100644 --- a/javascript/src/truth-table-generator/runner.node.ts +++ b/javascript/src/truth-table-generator/runner.node.ts @@ -31,11 +31,13 @@ import { writeJsonFile } from './util.js'; import { fuzzing } from './fuzzing.js'; -import { writeBddTemplate } from '../bdd/write-bdd-template.js'; +import { BDD_OPTIMIZE_STATE_LOCATION, writeBddTemplate } from '../bdd/write-bdd-template.js'; import { measurePerformanceOfStateFunctions, getBetterBdd, - getQualityOfBdd + getQualityOfBdd, + PerformanceMeasurement, + QUALITY_BY_BDD_CACHE } from './calculate-bdd-quality.js'; import { orderedStateList } from '../states/index.js'; @@ -59,6 +61,17 @@ function loadTruthTable() { ); return truthTable; } +function getQuality( + bdd: RootNode, + perfMeasurement: PerformanceMeasurement +) { + return getQualityOfBdd( + bdd, + perfMeasurement, + getQueryVariations(), + getTestProcedures() + ); +} const unknownValueActionId: number = 42; @@ -239,10 +252,14 @@ async function run() { bdd.removeIrrelevantLeafNodes(unknownValueActionId); bdd.log(); + const performanceMeasurement = await measurePerformanceOfStateFunctions(2000) + const quality = getQuality(bdd, performanceMeasurement); const bddMinimalString = bddToMinimalString(bdd); writeBddTemplate( - bddMinimalString + bddMinimalString, + performanceMeasurement, + quality ); console.log('nodes after minify: ' + bdd.countNodes()); @@ -265,28 +282,16 @@ async function run() { unknownValueActionId ); - let currentBest: RootNode; - - const perfMeasurement = await measurePerformanceOfStateFunctions(10000); - console.log('state function performance:'); - console.dir(perfMeasurement); - + const optimizeState = JSON.parse(fs.readFileSync(BDD_OPTIMIZE_STATE_LOCATION, 'utf-8')); + const performanceMeasurement = optimizeState.performanceMeasurement; + let currentBest: RootNode; const resolvers: ResolverFunctions = {}; new Array(orderedStateList.length).fill(0).forEach((_x, index) => { const fn = (state: string) => booleanStringToBoolean((state as any)[index]); resolvers[index] = fn; }); - function getQuality(bdd: RootNode) { - return getQualityOfBdd( - bdd, - perfMeasurement, - getQueryVariations(), - getTestProcedures() - ); - } - await optimizeBruteForce({ truthTable, iterations: 10000000, @@ -313,12 +318,11 @@ async function run() { } } - if (currentBest) { console.log( 'current best bdd has ' + currentBest.countNodes() + ' nodes ' + - 'and a quality of ' + getQuality(currentBest) + ' ' + - 'while newly tested one has quality of ' + getQuality(bdd) + 'and a quality of ' + getQuality(currentBest, performanceMeasurement) + ' ' + + 'while newly tested one has quality of ' + getQuality(bdd, performanceMeasurement) ); } else { currentBest = bdd; @@ -327,7 +331,7 @@ async function run() { compareResults: (a: RootNode, b: RootNode) => { const betterOne = getBetterBdd( a, b, - perfMeasurement, + performanceMeasurement, getQueryVariations(), getTestProcedures() ); @@ -338,19 +342,27 @@ async function run() { console.log('## Yeah! found better bdd ##'); lastBetterFoundTime = new Date().getTime(); const bddMinimalString = bddToMinimalString(currentBest); - const quality = getQuality(currentBest); + const quality = getQuality(currentBest, performanceMeasurement); console.log('nodes: ' + currentBest.countNodes()); console.log('quality(new): ' + quality); - console.log('quality(old): ' + getQuality(currentBest)); + console.log('quality(old): ' + getQuality(currentBest, performanceMeasurement)); console.log('new string: ' + bddMinimalString); currentBest = res.bdd; - writeBddTemplate( - bddMinimalString - ); - console.log('-'.repeat(100)); + const currentOptimizeState = JSON.parse(fs.readFileSync(BDD_OPTIMIZE_STATE_LOCATION, 'utf-8')); + if (quality > currentOptimizeState.quality) { + console.log('########## BETTER THEN BEFORE ! -> Save it'); + writeBddTemplate( + bddMinimalString, + performanceMeasurement, + quality + ); + console.log('-'.repeat(100)); + } else { + console.log('# DROP BECAUSE has better one with quality ' + currentOptimizeState.quality); + } }, - log: true + log: false }); })(); break;