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

Refactor flushevents #163

Closed
wants to merge 11 commits into from
4 changes: 4 additions & 0 deletions public/game/sketch.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ function setup() {
socket.on("updateSound", (data) => {
updateSound(data.soundInstances)
})
noLoop()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Esto para qué es? 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

la librería que utilizamos para dibujar, ejecuta un ciclo continuo llamando a la función draw(), redibujando todo aunque no hayan nuevos datos que dibujar (no se recibió ninguna actualización del backend). Habría que probarlo en otro entorno, pero en mi PC ocasionaba bastante uso de CPU.
Con este cambio lo que hice fue que la llamada a draw() sea manual, sólo cuando recibimos un evento. la contra de esto es que cuando exista un nuevo mensaje aún no implementado, hay que acordarse de llamar a draw() si queremos que se actualice el juego

loadBackground()
loadVisuals()
socket.emit("ready")
Expand Down Expand Up @@ -65,6 +66,7 @@ function loadBackground() {
fondo != "default" && imagen != null
? imagen.url
: defaultBackground
draw()
})
}

Expand All @@ -73,12 +75,14 @@ function loadAllImages() {
for (i = 0 ; i < img.length ; i++) {
images.push({ name: img[i].name, url: loadImage(`${img[i].url}`) })
}
draw()
})
}

function loadVisuals() {
socket.on("visuals", (visualsList) => {
visuals = visualsList
draw()
})
}

Expand Down
97 changes: 55 additions & 42 deletions src/commands/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@


const ioGame: Server | undefined = initializeGameClient(options)
const interpreter = game ? getGameInterpreter(environment, ioGame!) : interpret(environment, { ...natives })
const interpreter = game ? getGameInterpreter(environment) : interpret(environment, { ...natives })
const programPackage = environment.getNodeByFQN<Package>(programFQN).parent as Package
const dynamicDiagramClient = await initializeDynamicDiagram(programPackage, options, interpreter)

Expand All @@ -81,43 +81,9 @@
}
}

export const getGameInterpreter = (environment: Environment, io: Server): Interpreter => {
mind-ar marked this conversation as resolved.
Show resolved Hide resolved
const nativesAndDraw = {
...natives,
draw: {
drawer: {
*apply() {
try {
const game = interpreter?.object('wollok.game.game')
const visuals = getVisuals(game, interpreter)
io.emit('visuals', visuals)

const gameSounds = game.get('sounds')?.innerCollection ?? []
const mappedSounds = gameSounds.map(sound =>
[
sound.id,
sound.get('file')!.innerString!,
sound.get('status')!.innerString!,
sound.get('volume')!.innerNumber!,
sound.get('loop')!.innerBoolean!,
])
io.emit('updateSound', { soundInstances: mappedSounds })
} catch (error: any) {
logger.error(failureDescription(error instanceof WollokException ? error.message : 'Exception while executing the program'))
const debug = logger.getLevel() <= logger.levels.DEBUG
if (debug) logger.error(error)
interpreter.send('stop', gameSingleton)
}
},
},
},
}

const interpreter = interpret(environment, nativesAndDraw)

const gameSingleton = interpreter?.object(GAME_MODULE)
const drawer = interpreter.object('draw.drawer')
interpreter.send('onTick', gameSingleton, interpreter.reify(17), interpreter.reify('renderizar'), drawer)
// TODO: ver si se elimina este método
export const getGameInterpreter = (environment: Environment): Interpreter => {
mind-ar marked this conversation as resolved.
Show resolved Hide resolved
const interpreter = interpret(environment, natives)

return interpreter
}
Expand Down Expand Up @@ -197,7 +163,7 @@
queueEvent(interpreter, buildKeyPressEvent(interpreter, wKeyCode(key.key, key.keyCode)), buildKeyPressEvent(interpreter, 'ANY'))
})

const gameSingleton = interpreter?.object('wollok.game.game')
const gameSingleton = interpreter?.object(GAME_MODULE)
const background = gameSingleton.get('boardGround') ? gameSingleton.get('boardGround')?.innerString : 'default'

const baseFolder = join(project, assets)
Expand All @@ -213,11 +179,33 @@
socket.emit('background', background)
})

const flushInterval = 100
const flushInterval = 17
let muestras = 0
let tEvents = 0

const id = setInterval(() => {
try {
const tsStart = performance.now()

Check failure on line 188 in src/commands/run.ts

View workflow job for this annotation

GitHub Actions / test

Mixed spaces and tabs
interpreter.send('flushEvents', gameSingleton, interpreter.reify(timer))
timer += flushInterval

draw(interpreter, io)
const elapsed = performance.now() - tsStart
tEvents += elapsed

// Si flushEvents demoró más del tiempo flushInterval
// incrementamos el timer tomando el mayor de los tiempos
timer += elapsed > flushInterval ? elapsed : flushInterval
mind-ar marked this conversation as resolved.
Show resolved Hide resolved
muestras += 1


// cada 30 muestras se imprime por consola el tiempo promedio
// que tardó en procesar todos los eventos
if(muestras >= 30) {
logger.debug(`flushEvents: ${(tEvents / muestras).toFixed(2)} ms`)

Check failure on line 204 in src/commands/run.ts

View workflow job for this annotation

GitHub Actions / test

Mixed spaces and tabs
muestras = 0

Check failure on line 205 in src/commands/run.ts

View workflow job for this annotation

GitHub Actions / test

Mixed spaces and tabs
tEvents = 0

Check failure on line 206 in src/commands/run.ts

View workflow job for this annotation

GitHub Actions / test

Mixed spaces and tabs
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Esto se podría mover a una función aparte, y dejar la llamada comentada acá. Cosa de descomentar esa línea y ya tener info en algún lado.

Después podemos iterar la técnica.

Ojo que el linter marca que hay espacios raros.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Esto se podría mover a una función aparte, y dejar la llamada comentada acá. Cosa de descomentar esa línea y ya tener info en algún lado

si, pero si lo muevo tengo que hacer tEvent y muestras globales. Si te parece, lo hago

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lo que yo diría es de tener una función para profilear otra función. Y las variables que mencionás podrían estar "globales" en ese otro módulo.
Por ejemplo:

// profile.ts

let n = 0
let totalTime = 0
const hitCount = 30

export const profile = (f: () => any) => {
  const start = performance.now()
  f()
  const end = performance.now()
  totalTime += end - start
  n++
  if(n >= hitCount) {
     logger.debug(`flushEvents: ${(tEvents / muestras).toFixed(2)} ms`)
     n = 0
     totalTime = 0
  }
}

Y así se podría usar por ejemplo:

profile( () =>
        interpreter.send('flushEvents', gameSingleton, interpreter.reify(timer))
)

Que no es tan invasivo.

Después podemos ver si se puede mover a una annotation y controlarla globalmente para "prender y apagar" todos los profiles de una. Pero paso a paso.

Algo que también podría recibir la función es una etiqueta para tener contexto de lo que se está profilieando... ahora esa función tiene hardcodeado el flushEvents: en el string.

Sé que también hay otras funciones para loggear esto, podés ver por ejemplo el script cuando TS buildea el WRE: https://github.com/uqbar-project/wollok-ts/blob/master/scripts/buildWRE.ts


// We could pass the interpreter but a program does not change it
dynamicDiagramClient.onReload()
if (!gameSingleton.get('running')?.innerBoolean) {
Expand Down Expand Up @@ -291,4 +279,29 @@

export const dynamicDiagramPort = (port: string): string => `${+gamePort(port) + 1}`

const drawDefinition = () => parse.File('draw.wlk').tryParse('object drawer{ method apply() native }')
const drawDefinition = () => parse.File('draw.wlk').tryParse('object drawer{ method apply() native }')
mind-ar marked this conversation as resolved.
Show resolved Hide resolved


const draw = (interpreter: Interpreter, io: Server) => {
const game = interpreter?.object(GAME_MODULE)
try {
const visuals = getVisuals(game, interpreter)
io.emit('visuals', visuals)

const gameSounds = game.get('sounds')?.innerCollection ?? []
const mappedSounds = gameSounds.map(sound =>
[
sound.id,
sound.get('file')!.innerString!,
sound.get('status')!.innerString!,
sound.get('volume')!.innerNumber!,
sound.get('loop')!.innerBoolean!,
])
io.emit('updateSound', { soundInstances: mappedSounds })
} catch (error: any) {
logger.error(failureDescription(error instanceof WollokException ? error.message : 'Exception while executing the program'))
const debug = logger.getLevel() <= logger.levels.DEBUG
if (debug) logger.error(error)
interpreter.send('stop', game)
PalumboN marked this conversation as resolved.
Show resolved Hide resolved
}
}

Check warning on line 307 in src/commands/run.ts

View workflow job for this annotation

GitHub Actions / test

Newline not allowed at end of file
Loading