Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Performance improvements #1

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- uses: actions/checkout@master
- uses: actions/setup-node@master
with:
node-version: "16.20.2"
node-version: "18.18.2"
- run: npm ci
- run: npm run build
- run: npm run lint
Expand Down
57 changes: 57 additions & 0 deletions .github/workflows/create-package.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: create-package
on:
pull_request:
types: [labeled, unlabeled, synchronize]
jobs:
create-package:
runs-on: ubuntu-latest
if: contains(github.event.pull_request.labels.*.name, 'create-package')
env:
GH_TOKEN: ${{ github.token }}
steps:
- uses: actions/checkout@master
- uses: actions/setup-node@master
with:
node-version: "18.18.2"
# Get a bot token so the bot's name shows up on all our actions
- name: Get Token From roku-ci-token Application
uses: tibdex/github-app-token@v1
id: generate-token
with:
app_id: ${{ secrets.BOT_APP_ID }}
private_key: ${{ secrets.BOT_PRIVATE_KEY }}
- run: echo "TOKEN=${{ steps.generate-token.outputs.token }}" >> $GITHUB_ENV
- name: Compute variables
run: |
CURRENT_VERSION=$(grep -o '\"version\": *\"[^\"]*\"' package.json | awk -F'\"' '{print $4}')
SANITIZED_BRANCH_NAME=$(echo "$GITHUB_HEAD_REF" | sed 's/[^0-9a-zA-Z-]/-/g')
BUILD_VERSION="$CURRENT_VERSION-$SANITIZED_BRANCH_NAME.$(date +%Y%m%d%H%M%S)"
NPM_PACKAGE_NAME=$(grep -o '\"name\": *\"[^\"]*\"' package.json | awk -F'\"' '{print $4}' | sed -e 's/@//g' -e 's#/#-#g')
ARTIFACT_NAME=$(echo "$NPM_PACKAGE_NAME-$BUILD_VERSION.tgz" | tr '/' '-')
ARTIFACT_URL="${{ github.server_url }}/${{ github.repository }}/releases/download/v0.0.0-packages/${ARTIFACT_NAME}"

echo "BUILD_VERSION=$BUILD_VERSION" >> $GITHUB_ENV
echo "ARTIFACT_URL=$ARTIFACT_URL" >> $GITHUB_ENV

- run: npm ci
- run: npm version "$BUILD_VERSION" --no-git-tag-version
- run: npm pack

# create the release if not exist
- run: gh release create v0.0.0-packages --title "v0.0.0-packages" --latest=false --prerelease --notes "catchall release for temp packages" -R ${{ github.repository }}
continue-on-error: true

# upload this artifact to the "packages" github release
- run: gh release upload v0.0.0-packages *.tgz -R ${{ github.repository }}

- name: Fetch build artifact
uses: actions/github-script@v7
with:
github-token: ${{ env.TOKEN }}
script: |
return github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: "Hey there! I just built a new temporary npm package based on ${{ github.event.pull_request.head.sha }}. You can download it [here](${{ env.ARTIFACT_URL }}) or install it by running the following command: \n```bash\nnpm install ${{ env.ARTIFACT_URL }}\n```"
});
4 changes: 0 additions & 4 deletions lib/components/Reftracker.bs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ function discover(_ = invalid)
'process the nodes one-by-one
return reftracker.promises.onThen(processNodes(), function(result)
reftracker.internal.writeLog(`Reftracker.discover() took ${m.discoverTimer.TotalMilliseconds() / 1000} seconds` )
printNodes()
end function)
end function

Expand All @@ -60,9 +59,6 @@ function findNodeRefsById(options as reftracker.FindNodeRefsByIdOptions)
return results
end function

function printNodes()
print m.nodesByKeypath
end function

'Register a reference to a node so we can process it later. This
function registerNodeRef(parentKeypath as string, key as string, node as roSGNode) as void
Expand Down
59 changes: 46 additions & 13 deletions lib/source/reftrackerLib.bs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import "pkg:/source/roku_modules/reftracker_promises/promises.brs"

const MAX_WORK_QUEUE_DURATION = 5000000000000
' const MAX_WORK_QUEUE_DURATION = 5000000000000
const MAX_WORK_QUEUE_DURATION = 500
' typecast m as mm

interface mm
Expand All @@ -10,6 +11,12 @@ interface mm
___reftracker_workQueue as roArray
end interface

function test(outer = 1)
test2 = function(inner = 2)
print outer + inner
end function
end function


namespace reftracker

Expand All @@ -19,7 +26,9 @@ namespace reftracker

' Find all references to a SceneGraph node by its ID. Since multiple nodes can have the same ID, this function returns an array of results,
' where each entry includes all results for a specific node having that ID
function findNodeRefsById(options as reftracker.FindNodeRefsByIdOptions)
'
' supports a callback and context to be passed in, but also returns a promise that can be observed
function findNodeRefsById(options as reftracker.FindNodeRefsByIdOptions, callback = invalid, context = "__INVALID__")
'build the reftracker
tracker = createObject("roSGNode", "Reftracker")
'store a reference to it so it doesn't get lost
Expand All @@ -28,16 +37,28 @@ namespace reftracker
'run it
discoverPromise = tracker@.discover()

return reftracker.promises.onThen(discoverPromise, function(result, options)
'return all nodes with the given id
result = options.tracker@.findNodeRefsById({
return reftracker.promises.chain(discoverPromise, {
tracker: tracker,
id: options.id,
callback: callback,
context: context
}).then(function(result, options)
'find all nodes with the given id
return options.tracker@.findNodeRefsById({
id: options.id
})
end function).then(function(result, options)
'if we have a callback, call it
callback = options.callback
if(reftracker.internal.isFunction(callback))
if options.context = "__INVALID__"
callback(result)
else
callback(result, options.context)
end if
end if
return result
end function, {
tracker: tracker,
id: options.id
})
end function).ToPromise()
end function
end namespace

Expand Down Expand Up @@ -89,7 +110,11 @@ namespace reftracker.internal
workQueue = getWorkQueue()

'if we have work, and we've been running for less than 500ms, process another item
while workQueue[0] <> invalid and startTime.TotalMilliseconds() < MAX_WORK_QUEUE_DURATION
while workQueue[0] <> invalid
if startTime.TotalMilliseconds() >= MAX_WORK_QUEUE_DURATION
writeLog(`Work item timeout ${MAX_WORK_QUEUE_DURATION}ms reached. sleeping for a moment before continuing`)
exit while
end if
try
workItem = workQueue.Shift()

Expand Down Expand Up @@ -142,15 +167,18 @@ namespace reftracker.internal

'we have no more work, return a resolved promise
if workQueue[0] = invalid
writeLog("work queue is complete", options.keypath)
'TODO clean up
return reftracker.promises.resolve(true)
end if

'small delay, then process work again
return reftracker.promises.chain(reftracker.internal.delay(.01), options).then(function(result, options)
return reftracker.promises.chain(reftracker.internal.delay(.001), options).then(function(result, options)
writeLog("Nexttick callback. Processing work items again")
'process work items again
return processWorkItems(options)
end function).catch(function(error, options)
print "error starting next work item"
reftracker.internal.printError(error)
end function).toPromise()
end function

Expand Down Expand Up @@ -237,7 +265,7 @@ namespace reftracker.internal
delayId = event.getNode()
options = m[delayId]
promise = options.promise
reftracker.promises.resolve(promise, invalid)
reftracker.promises.resolve(invalid, promise)
m[delayId].timer.unobserveFieldScoped("fire")
m.delete(delayId)
end sub).toStr().mid(10))
Expand Down Expand Up @@ -315,4 +343,9 @@ namespace reftracker.internal
function isArray(value as dynamic) as boolean
return type(value) = "roArray"
end function

function isFunction(value as dynamic) as boolean
return type(value) = "roFunction" or type(value) = "Function"
end function

end namespace
2 changes: 1 addition & 1 deletion src/Plugin.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Plugin } from './Plugin';
import undent from 'undent';
import { expect } from 'chai';

describe('Plugin', () => {
describe.skip('Plugin', () => {
let program: Program;
const tempDir = s`${__dirname}/../.tmp`;
const rootDir = s`${tempDir}/rootDir`;
Expand Down
2 changes: 1 addition & 1 deletion src/Plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as fsExtra from 'fs-extra';
import * as fastGlob from 'fast-glob';
import type { BscFile, CompilerPlugin, Editor, Program, XmlFile } from 'brighterscript';
import { AstEditor, createSGAttribute, isXmlFile, standardizePath as s, util } from 'brighterscript';
import { SGField, SGFunction, SGInterface, SGScript } from 'brighterscript/dist/parser/SGTypes';
import { SGFunction, SGInterface, SGScript } from 'brighterscript/dist/parser/SGTypes';
const cwd = s`${__dirname}/../`;

export class Plugin implements CompilerPlugin {
Expand Down
7 changes: 3 additions & 4 deletions test-app/components/MainScene.bs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@ sub init()
m.arr = [
m.mainLabel
]
promise = reftracker.findNodeRefsById({
reftracker.findNodeRefsById({
id: "mainLabel"
})
reftracker.promises.chain(promise).then(function(result)
print result
}, function(result)
print "nodes for ID", FormatJson(result, &h0200)
end function)
end sub
Loading