mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-12 13:13:45 +01:00
Merge pull request #35966 from overleaf/bg-return-optimised-image-stats-and-timings
return image stats and timings in compile response GitOrigin-RevId: ec700b8cb6680bfd8f28ad0f1f2bbdb0479398bc
This commit is contained in:
@@ -138,6 +138,10 @@ const LATEX_MK_METRICS_STDERR = [
|
||||
],
|
||||
[
|
||||
'latexmk-img-times',
|
||||
/**
|
||||
* @param {string} s
|
||||
* @returns {Array<{type: string, count: number, time_ms: number}>}
|
||||
*/
|
||||
s => {
|
||||
const pngCategoriesByFile = new Map()
|
||||
const pngCopyMatches = s.matchAll(/^PNG copy: (.*)$/gm)
|
||||
@@ -157,6 +161,7 @@ const LATEX_MK_METRICS_STDERR = [
|
||||
/^Image written \((PNG|JPG|JBIG2|PDF), (\d+) ms\): (.*)$/gm
|
||||
)
|
||||
const timingsByType = new Map()
|
||||
const countByType = new Map()
|
||||
for (const match of timingMatches) {
|
||||
let type = match[1]
|
||||
const timeMs = parseInt(match[2], 10)
|
||||
@@ -174,9 +179,12 @@ const LATEX_MK_METRICS_STDERR = [
|
||||
|
||||
const accumulatedTime = timingsByType.get(type) ?? 0
|
||||
timingsByType.set(type, accumulatedTime + timeMs)
|
||||
const accumulatedCount = countByType.get(type) ?? 0
|
||||
countByType.set(type, accumulatedCount + 1)
|
||||
}
|
||||
return Array.from(timingsByType.entries()).map(([type, timeMs]) => ({
|
||||
type,
|
||||
count: countByType.get(type) || 0,
|
||||
time_ms: timeMs,
|
||||
}))
|
||||
},
|
||||
@@ -190,9 +198,10 @@ const LATEX_MK_METRICS_STDERR = [
|
||||
* `stats.latexmk` object.
|
||||
*
|
||||
* @param {{stdout?: string, stderr?: string}} output - The output from the latexmk process.
|
||||
* @param {{latexmk: object}} stats - The statistics object to update. This object is mutated.
|
||||
* @param {object} stats - The statistics object to update. This object is mutated.
|
||||
* @param {object} [timings] - The timings object to update. This object is mutated.
|
||||
*/
|
||||
function addLatexMkMetrics(output, stats) {
|
||||
function addLatexMkMetrics(output, stats, timings) {
|
||||
for (const [stat, matcher] of LATEX_MK_METRICS_STDOUT) {
|
||||
const match = matcher(output?.stdout || '', stats.latexmk)
|
||||
if (match) {
|
||||
@@ -205,6 +214,27 @@ function addLatexMkMetrics(output, stats) {
|
||||
stats.latexmk[stat] = match
|
||||
}
|
||||
}
|
||||
const imgTimings = stats.latexmk['latexmk-img-times']
|
||||
if (imgTimings) {
|
||||
let totalImageIncludeTime = 0
|
||||
let optimisedImageIncludeTime = 0
|
||||
let totalImageIncludeCount = 0
|
||||
let optimisedImageIncludeCount = 0
|
||||
for (const { type, count, time_ms } of imgTimings) {
|
||||
totalImageIncludeCount += count
|
||||
totalImageIncludeTime += time_ms
|
||||
if (type === 'PNG-png2pdf') {
|
||||
optimisedImageIncludeCount += count
|
||||
optimisedImageIncludeTime += time_ms
|
||||
}
|
||||
}
|
||||
stats['include-image-all'] = totalImageIncludeCount
|
||||
stats['include-image-optimised'] = optimisedImageIncludeCount
|
||||
if (timings) {
|
||||
timings['include-image-optimised'] = optimisedImageIncludeTime
|
||||
timings['include-image-all'] = totalImageIncludeTime
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -81,7 +81,7 @@ function runLatex(projectId, options, callback) {
|
||||
}
|
||||
if (stats.latexmk) {
|
||||
try {
|
||||
addLatexMkMetrics(output, stats)
|
||||
addLatexMkMetrics(output, stats, timings)
|
||||
} catch (err) {
|
||||
logger.error({ err, projectId }, 'error adding latexmk metrics')
|
||||
}
|
||||
|
||||
@@ -134,6 +134,8 @@ Hello world
|
||||
const expectedRuns = scenario.expectedRuns ?? 1
|
||||
// Note: chai's all.keys assertion rejects extra keys
|
||||
stats.should.have.all.keys(
|
||||
'include-image-all',
|
||||
'include-image-optimised',
|
||||
'isInitialCompile',
|
||||
'latexmk-errors',
|
||||
'latex-runs',
|
||||
@@ -148,6 +150,8 @@ Hello world
|
||||
'compile',
|
||||
'output',
|
||||
'compileE2E',
|
||||
'include-image-all',
|
||||
'include-image-optimised',
|
||||
...pdfCachingTimings
|
||||
)
|
||||
})
|
||||
|
||||
@@ -115,6 +115,7 @@ describe('LatexMetrics', function () {
|
||||
describe('addLatexMkMetrics', function () {
|
||||
beforeEach(function (ctx) {
|
||||
ctx.stats = {}
|
||||
ctx.timings = {}
|
||||
Object.defineProperty(ctx.stats, 'latexmk', {
|
||||
value: {},
|
||||
enumerable: false,
|
||||
@@ -128,34 +129,46 @@ describe('LatexMetrics', function () {
|
||||
'Image written (PNG, 100 ms): output/image1.png\n' +
|
||||
'Image written (JPG, 50 ms): output/image2.jpg\n',
|
||||
}
|
||||
addLatexMkMetrics(output, ctx.stats)
|
||||
addLatexMkMetrics(output, ctx.stats, ctx.timings)
|
||||
|
||||
expect(ctx.stats.latexmk['latexmk-img-times']).to.deep.equal([
|
||||
{ type: 'PNG', time_ms: 100 },
|
||||
{ type: 'JPG', time_ms: 50 },
|
||||
{ type: 'PNG', count: 1, time_ms: 100 },
|
||||
{ type: 'JPG', count: 1, time_ms: 50 },
|
||||
])
|
||||
expect(ctx.stats['include-image-all']).to.equal(2)
|
||||
expect(ctx.stats['include-image-optimised']).to.equal(0)
|
||||
expect(ctx.timings['include-image-all']).to.equal(150)
|
||||
expect(ctx.timings['include-image-optimised']).to.equal(0)
|
||||
})
|
||||
|
||||
it('should convert PDF type with .png extension to PNG-png2pdf', function (ctx) {
|
||||
const output = {
|
||||
stderr: 'Image written (PDF, 150 ms): image.png\n',
|
||||
}
|
||||
addLatexMkMetrics(output, ctx.stats)
|
||||
addLatexMkMetrics(output, ctx.stats, ctx.timings)
|
||||
|
||||
expect(ctx.stats.latexmk['latexmk-img-times']).to.deep.equal([
|
||||
{ type: 'PNG-png2pdf', time_ms: 150 },
|
||||
{ type: 'PNG-png2pdf', count: 1, time_ms: 150 },
|
||||
])
|
||||
expect(ctx.stats['include-image-all']).to.equal(1)
|
||||
expect(ctx.stats['include-image-optimised']).to.equal(1)
|
||||
expect(ctx.timings['include-image-all']).to.equal(150)
|
||||
expect(ctx.timings['include-image-optimised']).to.equal(150)
|
||||
})
|
||||
|
||||
it('should handle uppercase .PNG extension', function (ctx) {
|
||||
const output = {
|
||||
stderr: 'Image written (PDF, 200 ms): image.PNG\n',
|
||||
}
|
||||
addLatexMkMetrics(output, ctx.stats)
|
||||
addLatexMkMetrics(output, ctx.stats, ctx.timings)
|
||||
|
||||
expect(ctx.stats.latexmk['latexmk-img-times']).to.deep.equal([
|
||||
{ type: 'PNG-png2pdf', time_ms: 200 },
|
||||
{ type: 'PNG-png2pdf', count: 1, time_ms: 200 },
|
||||
])
|
||||
expect(ctx.stats['include-image-all']).to.equal(1)
|
||||
expect(ctx.stats['include-image-optimised']).to.equal(1)
|
||||
expect(ctx.timings['include-image-all']).to.equal(200)
|
||||
expect(ctx.timings['include-image-optimised']).to.equal(200)
|
||||
})
|
||||
|
||||
it('should keep PDF type for non-png extensions', function (ctx) {
|
||||
@@ -164,11 +177,15 @@ describe('LatexMetrics', function () {
|
||||
'Image written (PDF, 100 ms): document.pdf\n' +
|
||||
'Image written (PDF, 80 ms): image.jpg\n',
|
||||
}
|
||||
addLatexMkMetrics(output, ctx.stats)
|
||||
addLatexMkMetrics(output, ctx.stats, ctx.timings)
|
||||
|
||||
expect(ctx.stats.latexmk['latexmk-img-times']).to.deep.equal([
|
||||
{ type: 'PDF', time_ms: 180 },
|
||||
{ type: 'PDF', count: 2, time_ms: 180 },
|
||||
])
|
||||
expect(ctx.stats['include-image-all']).to.equal(2)
|
||||
expect(ctx.stats['include-image-optimised']).to.equal(0)
|
||||
expect(ctx.timings['include-image-all']).to.equal(180)
|
||||
expect(ctx.timings['include-image-optimised']).to.equal(0)
|
||||
})
|
||||
|
||||
it('should accumulate timing for the same type', function (ctx) {
|
||||
@@ -178,15 +195,19 @@ describe('LatexMetrics', function () {
|
||||
'Image written (PDF, 150 ms): image2.png\n' +
|
||||
'Image written (PNG, 50 ms): image3.png\n',
|
||||
}
|
||||
addLatexMkMetrics(output, ctx.stats)
|
||||
addLatexMkMetrics(output, ctx.stats, ctx.timings)
|
||||
|
||||
const result = ctx.stats.latexmk['latexmk-img-times'].sort((a, b) =>
|
||||
a.type.localeCompare(b.type)
|
||||
)
|
||||
expect(result).to.deep.equal([
|
||||
{ type: 'PNG', time_ms: 50 },
|
||||
{ type: 'PNG-png2pdf', time_ms: 250 },
|
||||
{ type: 'PNG', count: 1, time_ms: 50 },
|
||||
{ type: 'PNG-png2pdf', count: 2, time_ms: 250 },
|
||||
])
|
||||
expect(ctx.stats['include-image-all']).to.equal(3)
|
||||
expect(ctx.stats['include-image-optimised']).to.equal(2)
|
||||
expect(ctx.timings['include-image-all']).to.equal(300)
|
||||
expect(ctx.timings['include-image-optimised']).to.equal(250)
|
||||
})
|
||||
|
||||
it('should handle PNG with category from PNG copy skipped', function (ctx) {
|
||||
@@ -195,11 +216,15 @@ describe('LatexMetrics', function () {
|
||||
'PNG copy skipped (alpha): image1.png\n' +
|
||||
'Image written (PNG, 75 ms): image1.png\n',
|
||||
}
|
||||
addLatexMkMetrics(output, ctx.stats)
|
||||
addLatexMkMetrics(output, ctx.stats, ctx.timings)
|
||||
|
||||
expect(ctx.stats.latexmk['latexmk-img-times']).to.deep.equal([
|
||||
{ type: 'PNG-alpha', time_ms: 75 },
|
||||
{ type: 'PNG-alpha', count: 1, time_ms: 75 },
|
||||
])
|
||||
expect(ctx.stats['include-image-all']).to.equal(1)
|
||||
expect(ctx.stats['include-image-optimised']).to.equal(0)
|
||||
expect(ctx.timings['include-image-all']).to.equal(75)
|
||||
expect(ctx.timings['include-image-optimised']).to.equal(0)
|
||||
})
|
||||
|
||||
it('should mix PDF-to-png2pdf and PNG types', function (ctx) {
|
||||
@@ -209,16 +234,20 @@ describe('LatexMetrics', function () {
|
||||
'Image written (PNG, 50 ms): native.png\n' +
|
||||
'Image written (JPG, 30 ms): photo.jpg\n',
|
||||
}
|
||||
addLatexMkMetrics(output, ctx.stats)
|
||||
addLatexMkMetrics(output, ctx.stats, ctx.timings)
|
||||
|
||||
const result = ctx.stats.latexmk['latexmk-img-times'].sort((a, b) =>
|
||||
a.type.localeCompare(b.type)
|
||||
)
|
||||
expect(result).to.deep.equal([
|
||||
{ type: 'JPG', time_ms: 30 },
|
||||
{ type: 'PNG', time_ms: 50 },
|
||||
{ type: 'PNG-png2pdf', time_ms: 100 },
|
||||
{ type: 'JPG', count: 1, time_ms: 30 },
|
||||
{ type: 'PNG', count: 1, time_ms: 50 },
|
||||
{ type: 'PNG-png2pdf', count: 1, time_ms: 100 },
|
||||
])
|
||||
expect(ctx.stats['include-image-all']).to.equal(3)
|
||||
expect(ctx.stats['include-image-optimised']).to.equal(1)
|
||||
expect(ctx.timings['include-image-all']).to.equal(180)
|
||||
expect(ctx.timings['include-image-optimised']).to.equal(100)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -231,7 +260,7 @@ describe('LatexMetrics', function () {
|
||||
'PNG copy skipped (palette): palette.png\n' +
|
||||
'PNG copy skipped (other): other.png\n',
|
||||
}
|
||||
addLatexMkMetrics(output, ctx.stats)
|
||||
addLatexMkMetrics(output, ctx.stats, ctx.timings)
|
||||
|
||||
expect(ctx.stats.latexmk['latexmk-png-slow']).to.deep.equal([
|
||||
'images/alpha.png',
|
||||
@@ -242,7 +271,7 @@ describe('LatexMetrics', function () {
|
||||
|
||||
it('should not include fast PNG copy lines', function (ctx) {
|
||||
const output = { stderr: 'PNG copy: fast.png\n' }
|
||||
addLatexMkMetrics(output, ctx.stats)
|
||||
addLatexMkMetrics(output, ctx.stats, ctx.timings)
|
||||
|
||||
expect(ctx.stats.latexmk).to.not.have.property('latexmk-png-slow')
|
||||
})
|
||||
@@ -253,7 +282,7 @@ describe('LatexMetrics', function () {
|
||||
'PNG copy skipped (gamma): /compile/deep/img.png\n' +
|
||||
'PNG copy skipped (interlaced): ./local.png\n',
|
||||
}
|
||||
addLatexMkMetrics(output, ctx.stats)
|
||||
addLatexMkMetrics(output, ctx.stats, ctx.timings)
|
||||
|
||||
expect(ctx.stats.latexmk['latexmk-png-slow']).to.deep.equal([
|
||||
'deep/img.png',
|
||||
|
||||
Reference in New Issue
Block a user