Skip to content

Commit

Permalink
fix: adjust Node.js external memory while creating Canvas
Browse files Browse the repository at this point in the history
  • Loading branch information
Brooooooklyn committed Aug 16, 2022
1 parent 2a4c900 commit 77ecc52
Show file tree
Hide file tree
Showing 12 changed files with 175 additions and 9 deletions.
3 changes: 3 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
/// <reference lib="dom" />

// Clear all type of caches in Skia
export function clearAllCache(): void

export interface DOMMatrix2DInit {
a: number
b: number
Expand Down
2 changes: 2 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const { platform, homedir } = require('os')
const { join } = require('path')

const {
clearAllCache,
CanvasRenderingContext2D,
CanvasElement,
createContext,
Expand Down Expand Up @@ -195,6 +196,7 @@ if (!process.env.DISABLE_SYSTEM_FONTS_LOAD) {
}

module.exports = {
clearAllCache,
Canvas,
createCanvas,
Path2D,
Expand Down
2 changes: 2 additions & 0 deletions js-binding.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ if (!nativeBinding) {
}

const {
clearAllCache,
CanvasRenderingContext2D,
CanvasElement,
createContext,
Expand All @@ -212,6 +213,7 @@ const {
StrokeCap,
} = nativeBinding

module.exports.clearAllCache = clearAllCache
module.exports.CanvasRenderingContext2D = CanvasRenderingContext2D
module.exports.CanvasElement = CanvasElement
module.exports.createContext = createContext
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
"benny": "^3.7.1",
"canvas": "^2.9.1",
"canvaskit-wasm": "^0.35.0",
"colorette": "^2.0.16",
"colorette": "^2.0.19",
"conventional-changelog-cli": "^2.2.2",
"echarts": "^5.3.2",
"eslint": "^8.16.0",
Expand All @@ -91,7 +91,9 @@
"pinst": "^3.0.0",
"png.js": "^0.2.1",
"prettier": "^2.6.2",
"pretty-bytes": "^6.0.0",
"skia-canvas": "^1.0.0",
"table": "^6.8.0",
"typescript": "^4.7.2"
},
"lint-staged": {
Expand Down
66 changes: 66 additions & 0 deletions scripts/debug-memory.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { join } from 'node:path'
import { createRequire } from 'node:module'
import { setTimeout } from 'node:timers/promises'

import { whiteBright, red, green, gray } from 'colorette'
import prettyBytes from 'pretty-bytes'
import { table } from 'table'

import { createCanvas, Path2D, clearAllCache } from '../index.js'

function paint() {
const require = createRequire(import.meta.url)
const tiger = require('../example/tiger.json')
const canvas = createCanvas(6016, 3384)
const ctx = canvas.getContext('2d')
for (const pathObject of tiger) {
const p = new Path2D(pathObject.d)
ctx.fillStyle = pathObject.fillStyle
ctx.strokeStyle = pathObject.strokeStyle
if (pathObject.lineWidth) {
ctx.lineWidth = parseInt(pathObject.lineWidth, 10)
}
ctx.stroke(p)
ctx.fill(p)
}
}

const initial = process.memoryUsage()

async function main() {
for (const [index, _] of Array.from({ length: 100 }).entries()) {
displayMemoryUsageFromNode(initial)
await setTimeout(100)
global?.gc?.()
await paint()
}
}

main().then(() => {
displayMemoryUsageFromNode(initial)
clearAllCache()
global?.gc?.()
setInterval(() => {
displayMemoryUsageFromNode(initial)
}, 2000)
})

function displayMemoryUsageFromNode(initialMemoryUsage) {
const finalMemoryUsage = process.memoryUsage()
const titles = Object.keys(initialMemoryUsage).map((k) => whiteBright(k))
const tableData = [titles]
const diffColumn = []
for (const [key, value] of Object.entries(initialMemoryUsage)) {
const diff = finalMemoryUsage[key] - value
const prettyDiff = prettyBytes(diff, { signed: true })
if (diff > 0) {
diffColumn.push(red(prettyDiff))
} else if (diff < 0) {
diffColumn.push(green(prettyDiff))
} else {
diffColumn.push(gray(prettyDiff))
}
}
tableData.push(diffColumn)
console.info(table(tableData))
}
2 changes: 1 addition & 1 deletion scripts/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const REPO = 'canvas'
const [FULL_HASH] =
process.env.NODE_ENV === 'ava' ? ['000000'] : execSync(`git submodule status skia`).toString('utf8').trim().split(' ')

const SHORT_HASH = FULL_HASH.substr(0, 8)
const SHORT_HASH = FULL_HASH.substring(0, 8)

const TAG = `skia-${SHORT_HASH}`

Expand Down
5 changes: 5 additions & 0 deletions skia-c/skia_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ extern "C"
};
}

void skiac_clear_all_cache()
{
SkGraphics::PurgeAllCaches();
}

// Surface

static SkSurface *skiac_surface_create(int width, int height, SkAlphaType alphaType, uint8_t cs)
Expand Down
2 changes: 1 addition & 1 deletion skia-c/skia_c.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ struct skiac_mapped_point

extern "C"
{

void skiac_clear_all_cache();
// Surface
skiac_surface *skiac_surface_create_rgba_premultiplied(int width, int height, uint8_t cs);
void skiac_surface_create_svg(skiac_svg_surface *c_surface, int width, int height, int alphaType, uint32_t flag, uint8_t cs);
Expand Down
30 changes: 27 additions & 3 deletions src/ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ impl ImageOrCanvas {
}

pub struct Context {
env: Env,
pub(crate) surface: Surface,
path: Path,
pub alpha: bool,
Expand All @@ -53,6 +54,17 @@ pub struct Context {
pub stream: Option<SkWMemoryStream>,
}

impl Drop for Context {
fn drop(&mut self) {
if let Err(e) = self
.env
.adjust_external_memory(-((self.width * self.height * 4) as i64))
{
eprintln!("{e}");
}
}
}

impl Context {
pub fn create_js_class(env: &Env) -> Result<JsFunction> {
env.define_class(
Expand Down Expand Up @@ -242,6 +254,7 @@ impl Context {
}

pub fn new_svg(
env: Env,
width: u32,
height: u32,
svg_export_flag: SvgExportFlag,
Expand All @@ -256,6 +269,7 @@ impl Context {
)
.ok_or_else(|| Error::from_reason("Create skia svg surface failed".to_owned()))?;
Ok(Context {
env,
surface,
alpha: true,
path: Path::new(),
Expand All @@ -268,10 +282,11 @@ impl Context {
})
}

pub fn new(width: u32, height: u32, color_space: ColorSpace) -> Result<Self> {
pub fn new(env: Env, width: u32, height: u32, color_space: ColorSpace) -> Result<Self> {
let surface = Surface::new_rgba_premultiplied(width, height, color_space)
.ok_or_else(|| Error::from_reason("Create skia surface failed".to_owned()))?;
Ok(Context {
env,
surface,
alpha: true,
path: Path::new(),
Expand Down Expand Up @@ -845,12 +860,21 @@ fn context_2d_constructor(ctx: CallContext) -> Result<JsUndefined> {

let mut this = ctx.this_unchecked::<JsObject>();
let context_2d = if ctx.length == 3 {
Context::new(width, height, color_space)?
Context::new(*ctx.env, width, height, color_space)?
} else {
// SVG Canvas
let flag = ctx.get::<JsNumber>(3)?.get_uint32()?;
Context::new_svg(width, height, SvgExportFlag::try_from(flag)?, color_space)?
Context::new_svg(
*ctx.env,
width,
height,
SvgExportFlag::try_from(flag)?,
color_space,
)?
};
ctx
.env
.adjust_external_memory((width * height * 4) as i64)?;
ctx.env.wrap(&mut this, context_2d)?;
ctx.env.get_undefined()
}
Expand Down
5 changes: 5 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,3 +417,8 @@ impl SVGCanvas {
}
}
}

#[napi]
pub fn clear_all_cache() {
unsafe { sk::ffi::skiac_clear_all_cache() };
}
4 changes: 3 additions & 1 deletion src/sk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::error::SkError;
use crate::font::{FontStretch, FontStyle};
use crate::image::ImageData;

mod ffi {
pub mod ffi {
use std::ffi::c_void;
use std::os::raw::c_char;

Expand Down Expand Up @@ -247,6 +247,8 @@ mod ffi {
#[link(name = "skiac", kind = "static", cfg(target_os = "windows"))]
extern "C" {

pub fn skiac_clear_all_cache();

pub fn skiac_surface_create_rgba_premultiplied(
width: i32,
height: i32,
Expand Down
59 changes: 57 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ __metadata:
benny: ^3.7.1
canvas: ^2.9.1
canvaskit-wasm: ^0.35.0
colorette: ^2.0.16
colorette: ^2.0.19
conventional-changelog-cli: ^2.2.2
echarts: ^5.3.2
eslint: ^8.16.0
Expand All @@ -259,7 +259,9 @@ __metadata:
pinst: ^3.0.0
png.js: ^0.2.1
prettier: ^2.6.2
pretty-bytes: ^6.0.0
skia-canvas: ^1.0.0
table: ^6.8.0
typescript: ^4.7.2
languageName: unknown
linkType: soft
Expand Down Expand Up @@ -928,6 +930,18 @@ __metadata:
languageName: node
linkType: hard

"ajv@npm:^8.0.1":
version: 8.11.0
resolution: "ajv@npm:8.11.0"
dependencies:
fast-deep-equal: ^3.1.1
json-schema-traverse: ^1.0.0
require-from-string: ^2.0.2
uri-js: ^4.2.2
checksum: 5e0ff226806763be73e93dd7805b634f6f5921e3e90ca04acdf8db81eed9d8d3f0d4c5f1213047f45ebbf8047ffe0c840fa1ef2ec42c3a644899f69aa72b5bef
languageName: node
linkType: hard

"ansi-escapes@npm:^4.3.0":
version: 4.3.2
resolution: "ansi-escapes@npm:4.3.2"
Expand Down Expand Up @@ -1579,7 +1593,7 @@ __metadata:
languageName: node
linkType: hard

"colorette@npm:^2.0.16, colorette@npm:^2.0.17":
"colorette@npm:^2.0.16, colorette@npm:^2.0.17, colorette@npm:^2.0.19":
version: 2.0.19
resolution: "colorette@npm:2.0.19"
checksum: 888cf5493f781e5fcf54ce4d49e9d7d698f96ea2b2ef67906834bb319a392c667f9ec69f4a10e268d2946d13a9503d2d19b3abaaaf174e3451bfe91fb9d82427
Expand Down Expand Up @@ -3548,6 +3562,13 @@ __metadata:
languageName: node
linkType: hard

"json-schema-traverse@npm:^1.0.0":
version: 1.0.0
resolution: "json-schema-traverse@npm:1.0.0"
checksum: 02f2f466cdb0362558b2f1fd5e15cce82ef55d60cd7f8fa828cf35ba74330f8d767fcae5c5c2adb7851fa811766c694b9405810879bc4e1ddd78a7c0e03658ad
languageName: node
linkType: hard

"json-stable-stringify-without-jsonify@npm:^1.0.1":
version: 1.0.1
resolution: "json-stable-stringify-without-jsonify@npm:1.0.1"
Expand Down Expand Up @@ -3781,6 +3802,13 @@ __metadata:
languageName: node
linkType: hard

"lodash.truncate@npm:^4.4.2":
version: 4.4.2
resolution: "lodash.truncate@npm:4.4.2"
checksum: b463d8a382cfb5f0e71c504dcb6f807a7bd379ff1ea216669aa42c52fc28c54e404bfbd96791aa09e6df0de2c1d7b8f1b7f4b1a61f324d38fe98bc535aeee4f5
languageName: node
linkType: hard

"lodash@npm:^4.17.15, lodash@npm:^4.17.21, lodash@npm:^4.17.4":
version: 4.17.21
resolution: "lodash@npm:4.17.21"
Expand Down Expand Up @@ -4836,6 +4864,13 @@ __metadata:
languageName: node
linkType: hard

"pretty-bytes@npm:^6.0.0":
version: 6.0.0
resolution: "pretty-bytes@npm:6.0.0"
checksum: 0bb9f95e617236404b29a8392c6efd82d65805f622f5e809ecd70068102be857d4e3276c86d2a32fa2ef851cc29472e380945dab7bec83ec79bd57a19a10faf7
languageName: node
linkType: hard

"pretty-ms@npm:^7.0.1":
version: 7.0.1
resolution: "pretty-ms@npm:7.0.1"
Expand Down Expand Up @@ -5025,6 +5060,13 @@ __metadata:
languageName: node
linkType: hard

"require-from-string@npm:^2.0.2":
version: 2.0.2
resolution: "require-from-string@npm:2.0.2"
checksum: a03ef6895445f33a4015300c426699bc66b2b044ba7b670aa238610381b56d3f07c686251740d575e22f4c87531ba662d06937508f0f3c0f1ddc04db3130560b
languageName: node
linkType: hard

"resolve-cwd@npm:^3.0.0":
version: 3.0.0
resolution: "resolve-cwd@npm:3.0.0"
Expand Down Expand Up @@ -5649,6 +5691,19 @@ __metadata:
languageName: node
linkType: hard

"table@npm:^6.8.0":
version: 6.8.0
resolution: "table@npm:6.8.0"
dependencies:
ajv: ^8.0.1
lodash.truncate: ^4.4.2
slice-ansi: ^4.0.0
string-width: ^4.2.3
strip-ansi: ^6.0.1
checksum: 5b07fe462ee03d2e1fac02cbb578efd2e0b55ac07e3d3db2e950aa9570ade5a4a2b8d3c15e9f25c89e4e50b646bc4269934601ee1eef4ca7968ad31960977690
languageName: node
linkType: hard

"tar@npm:^6.1.11, tar@npm:^6.1.2":
version: 6.1.11
resolution: "tar@npm:6.1.11"
Expand Down

1 comment on commit 77ecc52

@github-actions
Copy link

Choose a reason for hiding this comment

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

Benchmark

Benchmark suite Current: 77ecc52 Previous: 2a4c900 Ratio
Draw house#skia-canvas 20.1 ops/sec (±0.55%) 21 ops/sec (±1.67%) 1.04
Draw house#node-canvas 17.8 ops/sec (±0.2%) 17 ops/sec (±1.86%) 0.96
Draw house#@napi-rs/skia 17.5 ops/sec (±1.85%) 18 ops/sec (±0.53%) 1.03
Draw gradient#skia-canvas 19.3 ops/sec (±0.48%) 21 ops/sec (±0.41%) 1.09
Draw gradient#node-canvas 17 ops/sec (±0.24%) 17 ops/sec (±0.24%) 1
Draw gradient#@napi-rs/skia 16.7 ops/sec (±1.07%) 18 ops/sec (±0.2%) 1.08

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.