add optimisable png count and compile stats to compile-with-optimizable-pngs event (#36279)

* add count of optimisable pngs to HistoryResourceWriter

* add optimisable png count and compile stats to compile-with-optimizable-pngs event

GitOrigin-RevId: 5c528d727473ec2d3082845d8d5b60844f3434f6
This commit is contained in:
Brian Gough
2026-09-17 11:49:41 +00:00
committed by Copybot
parent b8339c5b4a
commit 6b3d95cea4
4 changed files with 136 additions and 2 deletions
@@ -548,6 +548,7 @@ export async function syncResourcesToDisk(
// for analytics to determine if a project could have converted PNG's, even if they arent in the rollout
if (shouldConvert.size > 0) {
stats['optimisable-png-count'] = shouldConvert.size
stats.projectHasUnconvertedPngs = 1
}
@@ -251,6 +251,7 @@ describe('HistoryResourceWriter', function () {
// flagged slow, so it is not a conversion candidate.
const { stats } = await ctx.sync()
expect(stats.projectHasUnconvertedPngs).to.equal(undefined)
expect(stats['optimisable-png-count']).to.equal(undefined)
expect(ctx.convertPng.called).to.equal(false)
})
@@ -261,6 +262,7 @@ describe('HistoryResourceWriter', function () {
await ctx.HistoryResourceWriter.saveSlowPngList(ctx.cacheKey, ['fig.png'])
const { stats } = await ctx.sync({ png2pdf: false })
expect(stats.projectHasUnconvertedPngs).to.equal(1)
expect(stats['optimisable-png-count']).to.equal(1)
expect(ctx.convertPng.called).to.equal(false)
})
@@ -271,6 +273,7 @@ describe('HistoryResourceWriter', function () {
await ctx.HistoryResourceWriter.saveSlowPngList(ctx.cacheKey, ['fig.png'])
const { stats } = await ctx.sync({ png2pdf: true })
expect(stats.projectHasUnconvertedPngs).to.equal(1)
expect(stats['optimisable-png-count']).to.equal(1)
expect(ctx.convertPng.calledOnce).to.equal(true)
})
@@ -283,7 +286,42 @@ describe('HistoryResourceWriter', function () {
await ctx.HistoryResourceWriter.saveSlowPngList(ctx.cacheKey, ['fig.png'])
const { stats } = await ctx.sync({ png2pdf: true })
expect(stats.projectHasUnconvertedPngs).to.equal(undefined)
expect(stats['optimisable-png-count']).to.equal(undefined)
expect(ctx.convertPng.called).to.equal(false)
})
it('counts each convertible PNG separately when multiple are slow', async function (ctx) {
// With a single PNG, the count can never be more than 1 and so is
// indistinguishable from the boolean flag - add a second qualifying PNG
// to prove this field is an actual count.
ctx.rawSnapshot.files['fig2.png'] = {
hash: '1123456789012345678901234567890123456789',
byteLength: 2 * 1024 * 1024,
}
await ctx.HistoryResourceWriter.saveSlowPngList(ctx.cacheKey, [
'fig.png',
'fig2.png',
])
const { stats } = await ctx.sync({ png2pdf: true })
expect(stats.projectHasUnconvertedPngs).to.equal(1)
expect(stats['optimisable-png-count']).to.equal(2)
})
it('only counts the PNGs above the size threshold when slow PNGs are mixed', async function (ctx) {
// One slow PNG qualifies by size and one does not - the count must
// reflect only the size-filtered set, not the raw slow-list size.
ctx.rawSnapshot.files['fig.png'].byteLength = 512 * 1024 // below threshold
ctx.rawSnapshot.files['fig2.png'] = {
hash: '1123456789012345678901234567890123456789',
byteLength: 2 * 1024 * 1024, // above threshold
}
await ctx.HistoryResourceWriter.saveSlowPngList(ctx.cacheKey, [
'fig.png',
'fig2.png',
])
const { stats } = await ctx.sync({ png2pdf: true })
expect(stats.projectHasUnconvertedPngs).to.equal(1)
expect(stats['optimisable-png-count']).to.equal(1)
})
})
})
@@ -310,6 +310,8 @@ const _CompileController = {
// Projects the optimisation would never have touched are excluded,
// so they cannot dilute the comparison.
const optimisedPngCount = stats?.['include-image-optimised'] || 0
const optimisablePngCount =
stats?.['optimisable-png-count'] || stats?.['include-image-optimised']
const projectHasUnconvertedPngs = Boolean(stats?.projectHasUnconvertedPngs)
if (optimisedPngCount > 0 || projectHasUnconvertedPngs) {
AnalyticsManager.recordEventForUserInBackground(
@@ -317,6 +319,7 @@ const _CompileController = {
'compile-with-optimizable-pngs',
{
projectId,
optimizablePngCount: optimisablePngCount,
optimizedPngCount: optimisedPngCount,
optimizedImageInclusionTime:
timings?.['include-image-optimised'] || 0,
@@ -324,6 +327,9 @@ const _CompileController = {
totalImageInclusionTime: timings?.['include-image-all'] || 0,
isPng2pdf: !!options.png2pdf,
compiler: options.compiler,
compileTime: timings?.compileE2E,
isDraftMode: !!options.draft,
status,
}
)
}
@@ -443,10 +443,13 @@ describe('CompileController', function () {
status: 'success',
outputFiles: [],
stats: {
// clsi always sets 'optimisable-png-count' alongside
// projectHasUnconvertedPngs (see HistoryResourceWriter.js).
'optimisable-png-count': 1,
'include-image-all': 3,
projectHasUnconvertedPngs: 1,
},
timings: { 'include-image-all': 123 },
timings: { 'include-image-all': 123, compileE2E: 200 },
})
await ctx.CompileController.compile(ctx.req, ctx.res, ctx.next)
expect(
@@ -456,12 +459,16 @@ describe('CompileController', function () {
'compile-with-optimizable-pngs',
{
projectId: ctx.projectId,
optimizablePngCount: 1,
optimizedPngCount: 0,
optimizedImageInclusionTime: 0,
totalImages: 3,
totalImageInclusionTime: 123,
isPng2pdf: false,
compiler: undefined,
compileTime: 200,
isDraftMode: false,
status: 'success',
}
)
})
@@ -475,7 +482,11 @@ describe('CompileController', function () {
'include-image-all': 5,
projectHasUnconvertedPngs: 0,
},
timings: { 'include-image-optimised': 12, 'include-image-all': 34 },
timings: {
'include-image-optimised': 12,
'include-image-all': 34,
compileE2E: 300,
},
})
await ctx.CompileController.compile(ctx.req, ctx.res, ctx.next)
expect(
@@ -485,12 +496,90 @@ describe('CompileController', function () {
'compile-with-optimizable-pngs',
{
projectId: ctx.projectId,
// Falls back to the optimised-image count when 'optimisable-png-count'
// is absent from stats (e.g. an older clsi that predates the field).
optimizablePngCount: 2,
optimizedPngCount: 2,
optimizedImageInclusionTime: 12,
totalImages: 5,
totalImageInclusionTime: 34,
isPng2pdf: false,
compiler: undefined,
compileTime: 300,
isDraftMode: false,
status: 'success',
}
)
})
it('prefers the optimisable-png-count stat over the optimised-image count when both are present', async function (ctx) {
ctx.CompileManager.promises.compile.resolves({
status: 'success',
outputFiles: [],
stats: {
'optimisable-png-count': 5,
'include-image-optimised': 2,
'include-image-all': 5,
projectHasUnconvertedPngs: 1,
},
timings: {
'include-image-optimised': 12,
'include-image-all': 34,
compileE2E: 400,
},
})
await ctx.CompileController.compile(ctx.req, ctx.res, ctx.next)
expect(
ctx.AnalyticsManager.recordEventForUserInBackground
).to.have.been.calledWith(
ctx.user_id,
'compile-with-optimizable-pngs',
{
projectId: ctx.projectId,
optimizablePngCount: 5,
optimizedPngCount: 2,
optimizedImageInclusionTime: 12,
totalImages: 5,
totalImageInclusionTime: 34,
isPng2pdf: false,
compiler: undefined,
compileTime: 400,
isDraftMode: false,
status: 'success',
}
)
})
it('includes the compile status, compile time, and draft mode', async function (ctx) {
ctx.req.body = { draft: true }
ctx.CompileManager.promises.compile.resolves({
status: 'failure',
outputFiles: [],
stats: {
'optimisable-png-count': 1,
'include-image-all': 3,
projectHasUnconvertedPngs: 1,
},
timings: { 'include-image-all': 123, compileE2E: 456 },
})
await ctx.CompileController.compile(ctx.req, ctx.res, ctx.next)
expect(
ctx.AnalyticsManager.recordEventForUserInBackground
).to.have.been.calledWith(
ctx.user_id,
'compile-with-optimizable-pngs',
{
projectId: ctx.projectId,
optimizablePngCount: 1,
optimizedPngCount: 0,
optimizedImageInclusionTime: 0,
totalImages: 3,
totalImageInclusionTime: 123,
isPng2pdf: false,
compiler: undefined,
compileTime: 456,
isDraftMode: true,
status: 'failure',
}
)
})