From 91003b0bfe46c4e42c1714f9450917d0103c57ca Mon Sep 17 00:00:00 2001 From: guipublic Date: Thu, 28 Nov 2024 17:51:26 +0000 Subject: [PATCH] remove gate diffs and add memory report --- action.yml | 42 +-- src/format/contract.ts | 307 --------------------- src/format/program.ts | 460 -------------------------------- src/index.ts | 122 ++------- src/report.ts | 233 +++++----------- src/types.ts | 83 +----- tests/contract_report.test.ts | 87 ------ tests/diff.test.ts | 55 ---- tests/loading.test.ts | 16 -- tests/memory_report.test.ts | 26 ++ tests/mocks/1-1-mem_report.json | 16 ++ tests/mocks/1-2-mem_report.json | 16 ++ tests/mocks/mem_report.json | 338 +++++++++++++++++++++++ tests/program_report.test.ts | 196 -------------- 14 files changed, 493 insertions(+), 1504 deletions(-) delete mode 100644 src/format/contract.ts delete mode 100644 src/format/program.ts delete mode 100644 tests/contract_report.test.ts delete mode 100644 tests/diff.test.ts delete mode 100644 tests/loading.test.ts create mode 100644 tests/memory_report.test.ts create mode 100644 tests/mocks/1-1-mem_report.json create mode 100644 tests/mocks/1-2-mem_report.json create mode 100644 tests/mocks/mem_report.json delete mode 100644 tests/program_report.test.ts diff --git a/action.yml b/action.yml index d755f62..2c6a87c 100644 --- a/action.yml +++ b/action.yml @@ -1,6 +1,6 @@ -name: Generate gas diff -author: TomAFrench -description: Easily compare circuit size reports generated by Nargo! +name: Generate report +author: guipublic +description: Easily compare json reports branding: icon: info color: purple @@ -11,11 +11,11 @@ inputs: default: ${{ github.token }} required: false base: - description: The gates diff reference branch name. + description: The report reference branch name. default: ${{ github.base_ref || github.ref_name }} required: false head: - description: The gates diff target branch name. + description: The report target branch name. default: ${{ github.head_ref || github.ref_name }} required: false report: @@ -27,36 +27,16 @@ inputs: default: | # Changes to circuit sizes required: false - summaryQuantile: - description: The quantile threshold to filter avg gas cost diffs to display in the summary top section. - default: 0.8 - required: false - brillig_report: - description: States whether we want to generate a report of ACIR opcodes or Brillig opcodes. - default: false - brillig_report_bytes: - description: States whether the Brillig report is done with bytecode sizes rather than opcodes. - default: false - # sortCriteria: - # description: The list of criteria to order diff rows by in the report (name | min | avg | median | max | calls), separated by a comma. Must have the same length as sortOrders. - # required: false - # default: name - # sortOrders: - # description: The list of directions to order diff rows in the report, according to order criteria (asc | desc), separated by a comma. Must have the same length as sortCriteria. - # required: false - # default: asc - # ignore: - # description: The list of contract paths from which to ignore gates reports, separated by a comma. - # required: false - # match: - # description: The list of contract paths of which only to keep gates reports, separated by a comma. - # required: false + memory_report: + description: States whether we want to generate a report of memory usage. + default: false + required: false outputs: shell: - description: The gates diff between the base gates report and the freshly generated gates report, specifically formatted for shell display + description: The diff between the base report and the freshly generated report, specifically formatted for shell display markdown: - description: The gates diff between the base gates report and the freshly generated gates report, specifically formatted for markdown display + description: The diff between the base report and the freshly generated report, specifically formatted for markdown display runs: using: node16 diff --git a/src/format/contract.ts b/src/format/contract.ts deleted file mode 100644 index 440ed48..0000000 --- a/src/format/contract.ts +++ /dev/null @@ -1,307 +0,0 @@ -import colors from "colors"; -import _sortBy from "lodash/sortBy"; - -import { ContractDiffReport, DiffCell } from "../types"; - -import { - alignPattern, - center, - generateCommitInfo, - parenthesized, - plusSign, - TextAlign, -} from "./utils"; - -export const formatShellCell = (cell: DiffCell, length = 10) => { - const format = colors[cell.delta > 0 ? "red" : cell.delta < 0 ? "green" : "reset"]; - - return [ - cell.current.toLocaleString().padStart(length) + - " " + - format(parenthesized(plusSign(cell.delta) + cell.delta.toLocaleString()).padEnd(length)), - colors.bold( - format( - ( - plusSign(cell.percentage) + - (cell.percentage === Infinity ? "โˆž" : cell.percentage.toFixed(2)) + - "%" - ).padStart(9) - ) - ), - ]; -}; - -const selectSummaryDiffs = ( - diffs: ContractDiffReport[], - minCircuitChangePercentage: number -): ContractDiffReport[] => - diffs - .map(({ functions, ...diff }) => ({ - ...diff, - functions: functions.filter( - (method) => - Math.abs(method.circuit_size.percentage) >= minCircuitChangePercentage && - (method.opcodes.delta !== 0 || method.circuit_size.delta !== 0) - ), - })) - .filter((diff) => diff.functions.length > 0); - -export const formatShellDiff = (diffs: ContractDiffReport[], summaryQuantile = 0.8) => { - const maxContractLength = Math.max(8, ...diffs.map(({ name }) => name.length)); - const maxMethodLength = Math.max( - 7, - ...diffs.flatMap(({ functions }) => functions.map(({ name }) => name.length)) - ); - - const SHELL_SUMMARY_COLS = [ - { txt: "", length: 0 }, - { txt: "Contract", length: maxContractLength }, - { txt: "Method", length: maxMethodLength }, - { txt: "ACIR opcodes (+/-)", length: 33 }, - { txt: "Circuit size (+/-)", length: 33 }, - { txt: "", length: 0 }, - ]; - - const SHELL_DIFF_COLS = [ - { txt: "", length: 0 }, - { txt: "Contract", length: maxContractLength }, - { txt: "Method", length: maxMethodLength }, - { txt: "ACIR opcodes (+/-)", length: 33 }, - { txt: "Circuit size (+/-)", length: 33 }, - { txt: "", length: 0 }, - ]; - - const summaryHeader = SHELL_SUMMARY_COLS.map((entry) => - colors.bold(center(entry.txt, entry.length || 0)) - ) - .join(" | ") - .trim(); - const summarySeparator = SHELL_SUMMARY_COLS.map(({ length }) => - length > 0 ? "-".repeat(length + 2) : "" - ) - .join("|") - .trim(); - - const diffHeader = SHELL_DIFF_COLS.map((entry) => - colors.bold(center(entry.txt, entry.length || 0)) - ) - .join(" | ") - .trim(); - const diffSeparator = SHELL_DIFF_COLS.map(({ length }) => - length > 0 ? "-".repeat(length + 2) : "" - ) - .join("|") - .trim(); - - const sortedMethods = _sortBy( - diffs.flatMap((diff) => diff.functions), - (method) => Math.abs(method.circuit_size.percentage) - ); - const circuitChangeQuantile = Math.abs( - sortedMethods[Math.floor((sortedMethods.length - 1) * summaryQuantile)]?.circuit_size - .percentage ?? 0 - ); - - const summaryRows = selectSummaryDiffs(diffs, circuitChangeQuantile).flatMap((diff) => - diff.functions - .map((method, methodIndex) => - [ - "", - colors.bold(colors.grey((methodIndex === 0 ? diff.name : "").padEnd(maxContractLength))), - colors.italic(method.name.padEnd(maxMethodLength)), - ...formatShellCell(method.opcodes), - ...formatShellCell(method.circuit_size), - "", - ] - .join(" | ") - .trim() - ) - .join("\n") - .trim() - ); - - const fullReportRows = diffs.map((diff) => - diff.functions - .map((method, methodIndex) => - [ - "", - colors.bold(colors.grey((methodIndex === 0 ? diff.name : "").padEnd(maxContractLength))), - colors.italic(method.name.padEnd(maxMethodLength)), - ...formatShellCell(method.opcodes), - ...formatShellCell(method.circuit_size), - "", - ] - .join(" | ") - .trim() - ) - .join("\n") - .trim() - ); - - return ( - colors.underline( - colors.bold( - colors.yellow( - `๐Ÿงพ Summary (${Math.round((1 - summaryQuantile) * 100)}% most significant diffs)\n\n` - ) - ) - ) + - ["", summaryHeader, ...summaryRows, ""].join(`\n${summarySeparator}\n`).trim() + - colors.underline(colors.bold(colors.yellow("\n\nFull diff report ๐Ÿ‘‡\n\n"))) + - ["", diffHeader, ...fullReportRows, ""].join(`\n${diffSeparator}\n`).trim() - ); -}; - -const formatMarkdownSummaryCell = (rows: DiffCell[]) => [ - rows - .map( - (row) => - plusSign(row.delta) + - row.delta.toLocaleString() + - " " + - (row.delta > 0 ? "โŒ" : row.delta < 0 ? "โœ…" : "โž–") - ) - .join("
"), - rows - .map( - (row) => - "**" + - plusSign(row.percentage) + - (row.percentage === Infinity ? "โˆž" : row.percentage.toFixed(2)) + - "%**" - ) - .join("
"), -]; - -const formatMarkdownFullCell = (rows: DiffCell[]) => [ - rows - .map( - (row) => - row.current.toLocaleString() + - " (" + - plusSign(row.delta) + - row.delta.toLocaleString() + - ")" - ) - .join("
"), - rows - .map( - (row) => - "**" + - plusSign(row.percentage) + - (row.percentage === Infinity ? "โˆž" : row.percentage.toFixed(2)) + - "%**" - ) - .join("
"), -]; - -const MARKDOWN_SUMMARY_COLS = [ - { txt: "" }, - { txt: "Contract", align: TextAlign.LEFT }, - { txt: "Method", align: TextAlign.LEFT }, - { txt: "ACIR opcodes (+/-)", align: TextAlign.RIGHT }, - { txt: "%", align: TextAlign.RIGHT }, - { txt: "Circuit size (+/-)", align: TextAlign.RIGHT }, - { txt: "%", align: TextAlign.RIGHT }, - { txt: "" }, -]; - -const MARKDOWN_DIFF_COLS = [ - { txt: "" }, - { txt: "Contract", align: TextAlign.LEFT }, - { txt: "Method", align: TextAlign.LEFT }, - { txt: "ACIR opcodes (+/-)", align: TextAlign.RIGHT }, - { txt: "%", align: TextAlign.RIGHT }, - { txt: "Circuit size (+/-)", align: TextAlign.RIGHT }, - { txt: "%", align: TextAlign.RIGHT }, - { txt: "" }, -]; - -export const formatMarkdownDiff = ( - header: string, - diffs: ContractDiffReport[], - repository: string, - commitHash: string, - refCommitHash?: string, - summaryQuantile = 0.8 -) => { - const diffReport = [header, "", generateCommitInfo(repository, commitHash, refCommitHash)]; - if (diffs.length === 0) - return diffReport.concat(["", "### There are no changes in circuit sizes"]).join("\n").trim(); - - const summaryHeader = MARKDOWN_SUMMARY_COLS.map((entry) => entry.txt) - .join(" | ") - .trim(); - const summaryHeaderSeparator = MARKDOWN_SUMMARY_COLS.map((entry) => - entry.txt ? alignPattern(entry.align) : "" - ) - .join("|") - .trim(); - - const diffHeader = MARKDOWN_DIFF_COLS.map((entry) => entry.txt) - .join(" | ") - .trim(); - const diffHeaderSeparator = MARKDOWN_DIFF_COLS.map((entry) => - entry.txt ? alignPattern(entry.align) : "" - ) - .join("|") - .trim(); - - const sortedMethods = _sortBy( - diffs.flatMap((diff) => diff.functions), - (method) => Math.abs(method.circuit_size.percentage) - ); - const circuitChangeQuantile = Math.abs( - sortedMethods[Math.floor((sortedMethods.length - 1) * summaryQuantile)]?.circuit_size - .percentage ?? 0 - ); - - const summaryRows = selectSummaryDiffs(diffs, circuitChangeQuantile).flatMap((diff) => - [ - "", - `**${diff.name}**`, - diff.functions.map((method) => `_${method.name}_`).join("
"), - ...formatMarkdownSummaryCell(diff.functions.map((method) => method.opcodes)), - ...formatMarkdownSummaryCell(diff.functions.map((method) => method.circuit_size)), - "", - ] - .join(" | ") - .trim() - ); - - const fullReportRows = diffs.flatMap((diff) => - [ - "", - `**${diff.name}**`, - diff.functions.map((method) => `_${method.name}_`).join("
"), - ...formatMarkdownFullCell(diff.functions.map((method) => method.opcodes)), - ...formatMarkdownFullCell(diff.functions.map((method) => method.circuit_size)), - "", - ] - .join(" | ") - .trim() - ); - - return diffReport - .concat([ - "", - `### ๐Ÿงพ Summary (${Math.round((1 - summaryQuantile) * 100)}% most significant diffs)`, - "", - summaryHeader, - summaryHeaderSeparator, - ...summaryRows, - "---", - "", - "
", - "Full diff report ๐Ÿ‘‡", - "
", - "", - diffHeader, - diffHeaderSeparator, - ...fullReportRows, - "
", - "", - ]) - .join("\n") - .trim(); -}; diff --git a/src/format/program.ts b/src/format/program.ts deleted file mode 100644 index dadd360..0000000 --- a/src/format/program.ts +++ /dev/null @@ -1,460 +0,0 @@ -import colors from "colors"; -import _sortBy from "lodash/sortBy"; - -import { DiffBrillig, DiffCell, DiffCircuit } from "../types"; - -import { - alignPattern, - center, - generateCommitInfo, - parenthesized, - plusSign, - TextAlign, -} from "./utils"; - -export const formatShellCell = (cell: DiffCell, length = 10) => { - const format = colors[cell.delta > 0 ? "red" : cell.delta < 0 ? "green" : "reset"]; - - return [ - cell.current.toLocaleString().padStart(length) + - " " + - format(parenthesized(plusSign(cell.delta) + cell.delta.toLocaleString()).padEnd(length)), - colors.bold( - format( - ( - plusSign(cell.percentage) + - (cell.percentage === Infinity ? "โˆž" : cell.percentage.toFixed(2)) + - "%" - ).padStart(9) - ) - ), - ]; -}; - -const selectSummaryDiffs = ( - diffs: DiffCircuit[], - minCircuitChangePercentage: number -): DiffCircuit[] => - diffs.filter( - (method) => - Math.abs(method.circuit_size.percentage) >= minCircuitChangePercentage && - (method.opcodes.delta !== 0 || method.circuit_size.delta !== 0) - ); - -const selectSummaryDiffsBrillig = ( - diffs: DiffBrillig[], - minCircuitChangePercentage: number -): DiffBrillig[] => - diffs.filter( - (method) => - Math.abs(method.opcodes.percentage) >= minCircuitChangePercentage && - method.opcodes.delta !== 0 - ); - -export const formatShellCircuitRows = ( - diffs: DiffCircuit[], - summaryQuantile = 0.8 -): [string[], string[]] => { - const maxProgramLength = Math.max(8, ...diffs.map(({ name }) => name.length)); - - const sortedPrograms = _sortBy(diffs, (method) => Math.abs(method.circuit_size.percentage)); - const circuitChangeQuantile = Math.abs( - sortedPrograms[Math.floor((sortedPrograms.length - 1) * summaryQuantile)]?.circuit_size - .percentage ?? 0 - ); - - const summaryRows = selectSummaryDiffs(diffs, circuitChangeQuantile).map((diff) => - [ - "", - colors.bold(colors.grey(diff.name.padEnd(maxProgramLength))), - ...formatShellCell(diff.opcodes), - ...formatShellCell(diff.circuit_size), - "", - ] - .join(" | ") - .trim() - ); - - const fullReportRows = diffs.map((diff) => - [ - "", - colors.bold(colors.grey(diff.name.padEnd(maxProgramLength))), - ...formatShellCell(diff.opcodes), - ...formatShellCell(diff.circuit_size), - "", - ] - .join(" | ") - .trim() - ); - - return [summaryRows, fullReportRows]; -}; - -export const formatShellDiff = ( - diffs: DiffCircuit[], - summaryRows: string[], - fullReportRows: string[], - summaryQuantile = 0.8 -) => { - const maxProgramLength = Math.max(8, ...diffs.map(({ name }) => name.length)); - - const SHELL_SUMMARY_COLS = [ - { txt: "", length: 0 }, - { txt: "Program", length: maxProgramLength }, - { txt: "ACIR opcodes (+/-)", length: 33 }, - { txt: "Circuit size (+/-)", length: 33 }, - { txt: "", length: 0 }, - ]; - - const SHELL_DIFF_COLS = [ - { txt: "", length: 0 }, - { txt: "Program", length: maxProgramLength }, - { txt: "ACIR opcodes (+/-)", length: 33 }, - { txt: "Circuit size (+/-)", length: 33 }, - { txt: "", length: 0 }, - ]; - - const summaryHeader = SHELL_SUMMARY_COLS.map((entry) => - colors.bold(center(entry.txt, entry.length || 0)) - ) - .join(" | ") - .trim(); - const summarySeparator = SHELL_SUMMARY_COLS.map(({ length }) => - length > 0 ? "-".repeat(length + 2) : "" - ) - .join("|") - .trim(); - - const diffHeader = SHELL_DIFF_COLS.map((entry) => - colors.bold(center(entry.txt, entry.length || 0)) - ) - .join(" | ") - .trim(); - const diffSeparator = SHELL_DIFF_COLS.map(({ length }) => - length > 0 ? "-".repeat(length + 2) : "" - ) - .join("|") - .trim(); - - return ( - colors.underline( - colors.bold( - colors.yellow( - `๐Ÿงพ Summary (${Math.round((1 - summaryQuantile) * 100)}% most significant diffs)\n\n` - ) - ) - ) + - ["", summaryHeader, ...summaryRows, ""].join(`\n${summarySeparator}\n`).trim() + - colors.underline(colors.bold(colors.yellow("\n\nFull diff report ๐Ÿ‘‡\n\n"))) + - ["", diffHeader, ...fullReportRows, ""].join(`\n${diffSeparator}\n`).trim() - ); -}; - -export const formatShellBrilligRows = ( - diffs: DiffBrillig[], - summaryQuantile = 0.8 -): [string[], string[]] => { - const maxProgramLength = Math.max(8, ...diffs.map(({ name }) => name.length)); - - const sortedPrograms = _sortBy(diffs, (method) => Math.abs(method.opcodes.percentage)); - const circuitChangeQuantile = Math.abs( - sortedPrograms[Math.floor((sortedPrograms.length - 1) * summaryQuantile)]?.opcodes.percentage ?? - 0 - ); - - const summaryRows = selectSummaryDiffsBrillig(diffs, circuitChangeQuantile).map((diff) => - [ - "", - colors.bold(colors.grey(diff.name.padEnd(maxProgramLength))), - ...formatShellCell(diff.opcodes), - "", - ] - .join(" | ") - .trim() - ); - - const fullReportRows = diffs.map((diff) => - [ - "", - colors.bold(colors.grey(diff.name.padEnd(maxProgramLength))), - ...formatShellCell(diff.opcodes), - "", - ] - .join(" | ") - .trim() - ); - - return [summaryRows, fullReportRows]; -}; - -export const formatShellDiffBrillig = ( - diffs: DiffBrillig[], - summaryRows: string[], - fullReportRows: string[], - brillig_report_bytes: boolean, - summaryQuantile = 0.8 -) => { - const maxProgramLength = Math.max(8, ...diffs.map(({ name }) => name.length)); - - const SHELL_SUMMARY_COLS = [ - { txt: "", length: 0 }, - { txt: "Program", length: maxProgramLength }, - { txt: "Brillig opcodes (+/-)", length: 33 }, - { txt: "", length: 0 }, - ]; - - const SHELL_DIFF_COLS = [ - { txt: "", length: 0 }, - { txt: "Program", length: maxProgramLength }, - { txt: "Brillig opcodes (+/-)", length: 33 }, - { txt: "", length: 0 }, - ]; - - if (brillig_report_bytes) { - SHELL_SUMMARY_COLS[2].txt = "Bytecode size in bytes (+/-)"; - SHELL_DIFF_COLS[2].txt = "Bytecode size in bytes (+/-)"; - } - - const summaryHeader = SHELL_SUMMARY_COLS.map((entry) => - colors.bold(center(entry.txt, entry.length || 0)) - ) - .join(" | ") - .trim(); - const summarySeparator = SHELL_SUMMARY_COLS.map(({ length }) => - length > 0 ? "-".repeat(length + 2) : "" - ) - .join("|") - .trim(); - - const diffHeader = SHELL_DIFF_COLS.map((entry) => - colors.bold(center(entry.txt, entry.length || 0)) - ) - .join(" | ") - .trim(); - const diffSeparator = SHELL_DIFF_COLS.map(({ length }) => - length > 0 ? "-".repeat(length + 2) : "" - ) - .join("|") - .trim(); - - return ( - colors.underline( - colors.bold( - colors.yellow( - `๐Ÿงพ Summary (${Math.round((1 - summaryQuantile) * 100)}% most significant diffs)\n\n` - ) - ) - ) + - ["", summaryHeader, ...summaryRows, ""].join(`\n${summarySeparator}\n`).trim() + - colors.underline(colors.bold(colors.yellow("\n\nFull diff report ๐Ÿ‘‡\n\n"))) + - ["", diffHeader, ...fullReportRows, ""].join(`\n${diffSeparator}\n`).trim() - ); -}; - -const formatMarkdownSummaryCell = (rows: DiffCell[]) => [ - rows - .map( - (row) => - plusSign(row.delta) + - row.delta.toLocaleString() + - " " + - (row.delta > 0 ? "โŒ" : row.delta < 0 ? "โœ…" : "โž–") - ) - .join("
"), - rows - .map( - (row) => - "**" + - plusSign(row.percentage) + - (row.percentage === Infinity ? "โˆž" : row.percentage.toFixed(2)) + - "%**" - ) - .join("
"), -]; - -const formatMarkdownFullCell = (rows: DiffCell[]): string[] => [ - rows - .map( - (row) => - row.current.toLocaleString() + - " (" + - plusSign(row.delta) + - row.delta.toLocaleString() + - ")" - ) - .join("
"), - rows - .map( - (row) => - "**" + - plusSign(row.percentage) + - (row.percentage === Infinity ? "โˆž" : row.percentage.toFixed(2)) + - "%**" - ) - .join("
"), -]; - -const MARKDOWN_SUMMARY_COLS_CIRCUIT = [ - { txt: "" }, - { txt: "Program", align: TextAlign.LEFT }, - { txt: "ACIR opcodes (+/-)", align: TextAlign.RIGHT }, - { txt: "%", align: TextAlign.RIGHT }, - { txt: "Circuit size (+/-)", align: TextAlign.RIGHT }, - { txt: "%", align: TextAlign.RIGHT }, - { txt: "" }, -]; - -const MARKDOWN_DIFF_COLS_CIRCUIT = [ - { txt: "" }, - { txt: "Program", align: TextAlign.LEFT }, - { txt: "ACIR opcodes (+/-)", align: TextAlign.RIGHT }, - { txt: "%", align: TextAlign.RIGHT }, - { txt: "Circuit size (+/-)", align: TextAlign.RIGHT }, - { txt: "%", align: TextAlign.RIGHT }, - { txt: "" }, -]; - -const MARKDOWN_SUMMARY_COLS_BRILLIG = [ - { txt: "" }, - { txt: "Program", align: TextAlign.LEFT }, - { txt: "Brillig opcodes (+/-)", align: TextAlign.RIGHT }, - { txt: "%", align: TextAlign.RIGHT }, - { txt: "" }, -]; - -const MARKDOWN_DIFF_COLS_BRILLIG = [ - { txt: "" }, - { txt: "Program", align: TextAlign.LEFT }, - { txt: "Brillig opcodes (+/-)", align: TextAlign.RIGHT }, - { txt: "%", align: TextAlign.RIGHT }, - { txt: "" }, -]; - -export const formatCircuitRows = ( - diffs: DiffCircuit[], - summaryQuantile = 0.8 -): [string[], string[]] => { - const sortedMethods = _sortBy(diffs, (program) => Math.abs(program.circuit_size.percentage)); - const circuitChangeQuantile = Math.abs( - sortedMethods[Math.floor((sortedMethods.length - 1) * summaryQuantile)]?.circuit_size - .percentage ?? 0 - ); - - const summaryRows = selectSummaryDiffs(diffs, circuitChangeQuantile).flatMap((diff) => - [ - "", - `**${diff.name}**`, - ...formatMarkdownSummaryCell([diff.opcodes]), - ...formatMarkdownSummaryCell([diff.circuit_size]), - "", - ] - .join(" | ") - .trim() - ); - - const fullReportRows = diffs.flatMap((diff) => - [ - "", - `**${diff.name}**`, - ...formatMarkdownFullCell([diff.opcodes]), - ...formatMarkdownFullCell([diff.circuit_size]), - "", - ] - .join(" | ") - .trim() - ); - - return [summaryRows, fullReportRows]; -}; - -export const formatBrilligRows = ( - diffs: DiffBrillig[], - summaryQuantile = 0.8 -): [string[], string[]] => { - const sortedMethods = _sortBy(diffs, (program) => Math.abs(program.opcodes.percentage)); - const circuitChangeQuantile = Math.abs( - sortedMethods[Math.floor((sortedMethods.length - 1) * summaryQuantile)]?.opcodes.percentage ?? 0 - ); - - const summaryRows = selectSummaryDiffsBrillig(diffs, circuitChangeQuantile).flatMap((diff) => - ["", `**${diff.name}**`, ...formatMarkdownSummaryCell([diff.opcodes]), ""].join(" | ").trim() - ); - - const fullReportRows = diffs.flatMap((diff) => - ["", `**${diff.name}**`, ...formatMarkdownFullCell([diff.opcodes]), ""].join(" | ").trim() - ); - - return [summaryRows, fullReportRows]; -}; - -export const formatMarkdownDiff = ( - header: string, - repository: string, - commitHash: string, - summaryRows: string[], - fullReportRows: string[], - // Flag to distinguish the markdown columns that should be used - circuitReport: boolean, - brillig_report_bytes: boolean, - refCommitHash?: string, - summaryQuantile = 0.8 -) => { - const diffReport = [header, "", generateCommitInfo(repository, commitHash, refCommitHash)]; - if (fullReportRows.length === 0) - return diffReport.concat(["", "### There are no changes in sizes"]).join("\n").trim(); - - let MARKDOWN_SUMMARY_COLS; - let MARKDOWN_DIFF_COLS; - if (circuitReport) { - MARKDOWN_SUMMARY_COLS = MARKDOWN_SUMMARY_COLS_CIRCUIT; - MARKDOWN_DIFF_COLS = MARKDOWN_DIFF_COLS_CIRCUIT; - } else { - MARKDOWN_SUMMARY_COLS = MARKDOWN_SUMMARY_COLS_BRILLIG; - MARKDOWN_DIFF_COLS = MARKDOWN_DIFF_COLS_BRILLIG; - if (brillig_report_bytes) { - MARKDOWN_SUMMARY_COLS[2].txt = "Bytecode size in bytes (+/-)"; - MARKDOWN_DIFF_COLS[2].txt = "Bytecode size in bytes (+/-)"; - } - } - - const summaryHeader = MARKDOWN_SUMMARY_COLS.map((entry) => entry.txt) - .join(" | ") - .trim(); - const summaryHeaderSeparator = MARKDOWN_SUMMARY_COLS.map((entry) => - entry.txt ? alignPattern(entry.align) : "" - ) - .join("|") - .trim(); - - const diffHeader = MARKDOWN_DIFF_COLS.map((entry) => entry.txt) - .join(" | ") - .trim(); - const diffHeaderSeparator = MARKDOWN_DIFF_COLS.map((entry) => - entry.txt ? alignPattern(entry.align) : "" - ) - .join("|") - .trim(); - - return diffReport - .concat([ - "", - `### ๐Ÿงพ Summary (${Math.round((1 - summaryQuantile) * 100)}% most significant diffs)`, - "", - summaryHeader, - summaryHeaderSeparator, - ...summaryRows, - "---", - "", - "
", - "Full diff report ๐Ÿ‘‡", - "
", - "", - diffHeader, - diffHeaderSeparator, - ...fullReportRows, - "
", - "", - ]) - .join("\n") - .trim(); -}; diff --git a/src/index.ts b/src/index.ts index d25dd1c..b042ae4 100755 --- a/src/index.ts +++ b/src/index.ts @@ -6,25 +6,13 @@ import * as artifact from "@actions/artifact"; import * as core from "@actions/core"; import { context, getOctokit } from "@actions/github"; -import { - formatBrilligRows, - formatCircuitRows, - formatMarkdownDiff, - formatShellBrilligRows, - formatShellCircuitRows, - formatShellDiff, - formatShellDiffBrillig, -} from "./format/program"; -import { loadReports, computeProgramDiffs } from "./report"; +import { memoryReports, computeMemoryDiff } from "./report"; const token = process.env.GITHUB_TOKEN || core.getInput("token"); const report = core.getInput("report"); const header = core.getInput("header"); -const brillig_report = core.getInput("brillig_report"); -const brillig_report_bytes = core.getInput("brillig_report_bytes"); -const summaryQuantile = parseFloat(core.getInput("summaryQuantile")); -// const sortCriteria = core.getInput("sortCriteria").split(","); -// const sortOrders = core.getInput("sortOrders").split(","); +const memory_report = core.getInput("memory_report"); + const baseBranch = core.getInput("base"); const headBranch = core.getInput("head"); @@ -39,15 +27,15 @@ const { owner, repo } = context.repo; const repository = owner + "/" + repo; let referenceContent: string; +let compareContent: string; let refCommitHash: string | undefined; async function run() { - // if (!isSortCriteriaValid(sortCriteria)) return; - // if (!isSortOrdersValid(sortOrders)) return; - try { // Upload the gates report to be used as a reference in later runs. await uploadArtifact(); + core.info(`Loading reports from "${localReportPath}"`); + compareContent = fs.readFileSync(localReportPath, "utf8"); } catch (error) { return core.setFailed((error as Error).message); } @@ -59,17 +47,20 @@ async function run() { core.startGroup( `Searching artifact "${baseReport}" on repository "${repository}", on branch "${baseBranch}"` ); - + let count = 100; let artifactId: number | null = null; // Artifacts are returned in most recent first order. for await (const res of octokit.paginate.iterator(octokit.rest.actions.listArtifactsForRepo, { owner, repo, })) { + if (count == 0) { + break; + } const artifact = res.data.find( (artifact) => !artifact.expired && artifact.name === baseReport ); - + count = count - 1; if (!artifact) { await new Promise((resolve) => setTimeout(resolve, 900)); // avoid reaching the API rate limit @@ -98,7 +89,7 @@ async function run() { const zip = new Zip(Buffer.from(res.data as ArrayBuffer)); for (const entry of zip.getEntries()) { - core.info(`Loading gas reports from "${entry.entryName}"`); + core.info(`Loading reports from "${entry.entryName}"`); referenceContent = zip.readAsText(entry); } core.endGroup(); @@ -109,89 +100,18 @@ async function run() { } try { - core.startGroup("Load gas reports"); - core.info(`Loading gas reports from "${localReportPath}"`); - const compareContent = fs.readFileSync(localReportPath, "utf8"); - referenceContent ??= compareContent; // if no source gas reports were loaded, defaults to the current gas reports - - core.info(`Mapping compared gas reports`); - const compareReports = loadReports(compareContent); - core.info(`Got ${compareReports.programs.length} compare programs`); - - core.info(`Mapping reference gas reports`); - const referenceReports = loadReports(referenceContent); - core.info(`Got ${compareReports.programs.length} reference programs`); - core.endGroup(); - - core.startGroup("Compute gas diff"); - const [diffCircuitRows, diffBrilligRows] = computeProgramDiffs( - referenceReports.programs, - compareReports.programs - ); - - let numDiffs = diffCircuitRows.length; - let summaryRows; - let fullReportRows; - if (brillig_report) { - numDiffs = diffBrilligRows.length; - core.info(`Format Brillig markdown rows`); - [summaryRows, fullReportRows] = formatBrilligRows(diffBrilligRows, summaryQuantile); - } else { - core.info(`Format ACIR markdown rows`); - [summaryRows, fullReportRows] = formatCircuitRows(diffCircuitRows, summaryQuantile); - } - - core.info(`Format markdown of ${numDiffs} diffs`); - // const [summaryRows, fullReportRows] = formatCircuitRows(diffCircuitRows, summaryQuantile); - const markdown = formatMarkdownDiff( - header, - repository, - context.sha, - summaryRows, - fullReportRows, - !brillig_report, - brillig_report_bytes == "true", - refCommitHash, - summaryQuantile - ); - core.info(`Format shell of ${numDiffs} diffs`); - - let shell; - if (brillig_report) { - core.info(`Format Brillig diffs`); - const [summaryRowsShell, fullReportRowsShell] = formatShellBrilligRows( - diffBrilligRows, - summaryQuantile - ); - shell = formatShellDiffBrillig( - diffCircuitRows, - summaryRowsShell, - fullReportRowsShell, - brillig_report_bytes == "true", - summaryQuantile - ); - } else { - core.info(`Format ACIR diffs`); - const [summaryRowsShell, fullReportRowsShell] = formatShellCircuitRows( - diffCircuitRows, - summaryQuantile - ); - shell = formatShellDiff( - diffCircuitRows, - summaryRowsShell, - fullReportRowsShell, - summaryQuantile - ); + core.startGroup("Load reports"); + referenceContent ??= compareContent; // if no source reports were loaded, defaults to the current reports + + if (memory_report) { + core.info(`Format Memory markdown rows`); + const memoryContent = memoryReports(compareContent); + const referenceReports = memoryReports(referenceContent); + const markdown = computeMemoryDiff(referenceReports, memoryContent); + core.setOutput("markdown", markdown); } core.endGroup(); - - console.log(shell); - - if (numDiffs > 0) { - core.setOutput("shell", shell); - core.setOutput("markdown", markdown); - } } catch (error) { core.setFailed((error as Error).message); } diff --git a/src/report.ts b/src/report.ts index 6509fb8..0339237 100644 --- a/src/report.ts +++ b/src/report.ts @@ -1,16 +1,6 @@ import _orderBy from "lodash/orderBy"; -import { - ContractDiffReport, - ContractReport, - DiffCircuit, - CircuitReport, - WorkspaceDiffReport, - WorkspaceReport, - ProgramReport, - BrilligReport, - DiffBrillig, -} from "./types"; +import { MemoryReport } from "./types"; export const variation = (current: number, previous: number) => { const delta = current - previous; @@ -23,173 +13,70 @@ export const variation = (current: number, previous: number) => { }; }; -export const loadReports = (content: string): WorkspaceReport => { - return JSON.parse(content); +export const memoryReports = (content: string): MemoryReport[] => { + return JSON.parse(content).memory_reports; }; -export const computedWorkspaceDiff = ( - sourceReport: WorkspaceReport, - compareReport: WorkspaceReport -): WorkspaceDiffReport => { - const [diffCircuits, diffBrilligs] = computeProgramDiffs( - sourceReport.programs, - compareReport.programs - ); - return { - programs: diffCircuits, - unconstrained_functions: diffBrilligs, - contracts: computeContractDiffs(sourceReport.contracts, compareReport.contracts), - }; -}; - -export const computeProgramDiffs = ( - sourceReports: ProgramReport[], - compareReports: ProgramReport[] -): [DiffCircuit[], DiffBrillig[]] => { - const sourceReportNames = sourceReports.map((report) => report.package_name); - const commonReportNames = compareReports - .map((report) => report.package_name) - .filter((name) => sourceReportNames.includes(name)); - - const diffCircuits = commonReportNames - .map((reportName) => { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const srcReport = sourceReports.find((report) => report.package_name == reportName)!; - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const cmpReport = compareReports.find((report) => report.package_name == reportName)!; - - // For now we fetch just the main of each program - return computeCircuitDiff(srcReport.functions[0], cmpReport.functions[0], reportName); - }) - .filter((diff) => !isEmptyDiff(diff)) - .sort( - (diff1, diff2) => - Math.max(diff2.circuit_size.percentage) - Math.max(diff1.circuit_size.percentage) +export const formatMemoryReport = (memReports: MemoryReport[]): string => { + let markdown = "## Peak Memory Sample\n | Program | Peak Memory |\n | --- | --- |\n"; + for (let i = 0; i < memReports.length; i++) { + markdown = markdown.concat( + " | ", + memReports[i].artifact_name, + " | ", + memReports[i].peak_memory, + " |\n" ); + } + return markdown; +}; - const diffBrilligs = commonReportNames - .map((reportName) => { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const srcReport = sourceReports.find((report) => report.package_name == reportName)!; - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const cmpReport = compareReports.find((report) => report.package_name == reportName)!; - - if ( - srcReport.unconstrained_functions.length === 0 || - cmpReport.unconstrained_functions.length === 0 - ) { - return { - name: "", - opcodes: { - previous: 0, - current: 0, - delta: 0, - percentage: 0, - }, - }; +export const computeMemoryDiff = ( + refReports: MemoryReport[], + memReports: MemoryReport[] +): string => { + let markdown = ""; + const diff_percentage = []; + let diff_column = false; + if (refReports.length === memReports.length) { + for (let i = 0; i < refReports.length; i++) { + let diff_str = "N/A"; + if (refReports[i].artifact_name === memReports[i].artifact_name) { + const compPeak = memReports[i].peak_memory; + const refPeak = refReports[i].peak_memory; + let diff = 0; + if (compPeak[compPeak.length - 1] == refPeak[refPeak.length - 1]) { + const compPeakValue = parseInt(compPeak.substring(0, compPeak.length - 1)); + const refPeakValue = parseInt(refPeak.substring(0, refPeak.length - 1)); + diff = Math.floor(((compPeakValue - refPeakValue) / refPeakValue) * 100); + } else { + diff = 100; + } + if (diff != 0) { + diff_column = true; + } + diff_str = diff.toString() + "%"; } - // For now we fetch just the main of each program - return computeUnconstrainedDiff( - srcReport.unconstrained_functions[0], - cmpReport.unconstrained_functions[0], - reportName + diff_percentage.push(diff_str); + } + } + + if (diff_column == true) { + markdown = "## Peak Memory Sample\n | Program | Peak Memory | % |\n | --- | --- | --- |\n"; + for (let i = 0; i < memReports.length; i++) { + markdown = markdown.concat( + " | ", + memReports[i].artifact_name, + " | ", + memReports[i].peak_memory, + " | ", + diff_percentage[i], + " |\n" ); - }) - .filter((diff) => !isEmptyDiffBrillig(diff)) - .sort( - (diff1, diff2) => Math.max(diff2.opcodes.percentage) - Math.max(diff1.opcodes.percentage) - ); - - return [diffCircuits, diffBrilligs]; -}; - -const computeCircuitDiff = ( - sourceReport: CircuitReport, - compareReport: CircuitReport, - // We want the name of the package that represents the entire program in our report - reportName: string -): DiffCircuit => { - return { - name: reportName, - opcodes: variation(compareReport.opcodes, sourceReport.opcodes), - circuit_size: variation(compareReport.circuit_size, sourceReport.circuit_size), - }; -}; + } + } else { + markdown = formatMemoryReport(memReports); + } -const computeUnconstrainedDiff = ( - sourceReport: BrilligReport, - compareReport: BrilligReport, - // We want the name of the package that represents the entire program in our report - reportName: string -): DiffBrillig => { - return { - name: reportName, - opcodes: variation(compareReport.opcodes, sourceReport.opcodes), - }; -}; - -const isEmptyDiff = (diff: DiffCircuit): boolean => - diff.opcodes.delta === 0 && diff.circuit_size.delta === 0; - -const isEmptyDiffBrillig = (diff: DiffBrillig): boolean => diff.opcodes.delta === 0; - -export const computeContractDiffs = ( - sourceReports: ContractReport[], - compareReports: ContractReport[] -): ContractDiffReport[] => { - const sourceReportNames = sourceReports.map((report) => report.name); - const commonReportNames = compareReports - .map((report) => report.name) - .filter((name) => sourceReportNames.includes(name)); - - return commonReportNames - .map((reportName) => { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const srcReport = sourceReports.find((report) => report.name == reportName)!; - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const cmpReport = compareReports.find((report) => report.name == reportName)!; - - return computeContractDiff(srcReport, cmpReport); - }) - .filter((diff) => diff.functions.length > 0) - .sort( - (diff1, diff2) => - Math.max( - ...diff2.functions.map((functionDiff) => Math.abs(functionDiff.circuit_size.percentage)) - ) - - Math.max( - ...diff1.functions.map((functionDiff) => Math.abs(functionDiff.circuit_size.percentage)) - ) - ); -}; - -const computeContractDiff = ( - sourceReport: ContractReport, - compareReport: ContractReport -): ContractDiffReport => { - // TODO(https://github.com/noir-lang/noir/issues/4720): Settle on how to display contract functions with non-inlined Acir calls - // Right now we assume each contract function does not have non-inlined functions. - // Thus, we simply re-assign each `CircuitReport` to a `ProgramReport` to easily reuse `computeProgramDiffs` - const sourceFunctionsAsProgram = sourceReport.functions.map((func) => { - const programReport: ProgramReport = { - package_name: func.name, - functions: [func], - unconstrained_functions: [], - }; - return programReport; - }); - const compareFunctionsAsProgram = compareReport.functions.map((func) => { - const programReport: ProgramReport = { - package_name: func.name, - functions: [func], - unconstrained_functions: [], - }; - return programReport; - }); - const [functionDiffs] = computeProgramDiffs(sourceFunctionsAsProgram, compareFunctionsAsProgram); - - return { - name: sourceReport.name, - functions: functionDiffs, - }; + return markdown; }; diff --git a/src/types.ts b/src/types.ts index 6927651..2f9018f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,83 +1,10 @@ import * as core from "@actions/core"; -export interface CircuitReport { - name: string; - opcodes: number; - circuit_size: number; +export interface MemoryReport { + artifact_name: string; + peak_memory: string; } -export interface BrilligReport { - name: string; - opcodes: number; +export interface MemoryReports { + memory_reports: MemoryReport[]; } - -export interface ProgramReport { - // Name of the program package - package_name: string; - functions: CircuitReport[]; - unconstrained_functions: BrilligReport[]; -} - -export interface ContractReport { - name: string; - // TODO(https://github.com/noir-lang/noir/issues/4720): Settle on how to display contract functions with non-inlined Acir calls - functions: CircuitReport[]; -} - -export interface WorkspaceReport { - programs: ProgramReport[]; - contracts: ContractReport[]; -} - -export interface WorkspaceDiffReport { - programs: DiffCircuit[]; - unconstrained_functions: DiffBrillig[]; - contracts: ContractDiffReport[]; -} - -export interface ContractDiffReport { - name: string; - functions: DiffCircuit[]; -} - -export interface DiffCircuit { - name: string; - opcodes: DiffCell; - circuit_size: DiffCell; -} - -export interface DiffBrillig { - name: string; - opcodes: DiffCell; -} - -export interface DiffCell { - previous: number; - current: number; - delta: number; - percentage: number; -} - -export type SortCriterion = keyof DiffCircuit; -export type SortOrder = "asc" | "desc"; - -const validSortCriteria = ["name", "opcodes", "circuit_size"] as SortCriterion[]; -const validSortOrders = ["asc", "desc"] as SortOrder[]; - -export const isSortCriteriaValid = (sortCriteria: string[]): sortCriteria is SortCriterion[] => { - const invalidSortCriterion = sortCriteria.find( - (criterion) => !validSortCriteria.includes(criterion as SortCriterion) - ); - if (invalidSortCriterion) core.setFailed(`Invalid sort criterion "${invalidSortCriterion}"`); - - return !invalidSortCriterion; -}; - -export const isSortOrdersValid = (sortOrders: string[]): sortOrders is SortOrder[] => { - const invalidSortOrder = sortOrders.find( - (order) => !validSortOrders.includes(order as SortOrder) - ); - if (invalidSortOrder) core.setFailed(`Invalid sort order "${invalidSortOrder}"`); - - return !invalidSortOrder; -}; diff --git a/tests/contract_report.test.ts b/tests/contract_report.test.ts deleted file mode 100644 index f69cbbc..0000000 --- a/tests/contract_report.test.ts +++ /dev/null @@ -1,87 +0,0 @@ -import * as fs from "fs"; - -import { formatMarkdownDiff, formatShellDiff } from "../src/format/contract"; -import { loadReports, computeContractDiffs } from "../src/report"; - -const srcContent = fs.readFileSync("tests/mocks/gas_report.2.json", "utf8"); -const cmpContent = fs.readFileSync("tests/mocks/gas_report.1.json", "utf8"); - -const srcContractReports = loadReports(srcContent).contracts; -const cmpContractReports = loadReports(cmpContent).contracts; - -describe("Markdown format", () => { - // shows how the runner will run a javascript action with env / stdout protocol - // it("should run action", () => { - // const np = process.execPath; - // const ip = path.join(__dirname, "..", "dist", "index.js"); - // console.log( - // cp - // .execFileSync(np, [ip], { - // env: { - // ...process.env, - // INPUT_WORKFLOWID: "test", - // INPUT_BASE: "base", - // INPUT_HEAD: "head", - // GITHUB_TOKEN: "token", - // INPUT_REPORT: "report", - // }, - // }) - // .toString() - // ); - // }); - - it("should compare 1 to 2 with markdown format", () => { - const contractDiffs = computeContractDiffs(srcContractReports, cmpContractReports); - expect(contractDiffs.length).toBeGreaterThan(0); - - fs.writeFileSync( - "tests/mocks/1-2-contract.md", - formatMarkdownDiff( - "# Changes to gas cost", - contractDiffs, - "Rubilmax/foundry-gas-diff", - "d62d23148ca73df77cd4378ee1b3c17f1f303dbf", - undefined, - 0.8 - ) - ); - }); - - it("should compare 1 to 1 with markdown format", () => { - const contractDiffs = computeContractDiffs(srcContractReports, srcContractReports); - expect(contractDiffs.length).toBe(0); - - fs.writeFileSync( - "tests/mocks/1-1-contract.md", - formatMarkdownDiff( - "# Changes to gas cost", - contractDiffs, - "Rubilmax/foundry-gas-diff", - "d62d23148ca73df77cd4378ee1b3c17f1f303dbf" - ) - ); - }); -}); - -describe("Shell format", () => { - it("should compare 1 to 1", () => { - const contractDiffs = computeContractDiffs(srcContractReports, srcContractReports); - expect(contractDiffs.length).toBe(0); - - console.log(formatShellDiff(contractDiffs)); - }); - - it("should compare 1 to 2", () => { - const contractDiffs = computeContractDiffs(srcContractReports, cmpContractReports); - expect(contractDiffs.length).toBeGreaterThan(0); - - console.log(formatShellDiff(contractDiffs)); - }); - - it("should compare 2 to 1", () => { - const contractDiffs = computeContractDiffs(cmpContractReports, srcContractReports); - expect(contractDiffs.length).toBeGreaterThan(0); - - console.log(formatShellDiff(contractDiffs)); - }); -}); diff --git a/tests/diff.test.ts b/tests/diff.test.ts deleted file mode 100644 index d942187..0000000 --- a/tests/diff.test.ts +++ /dev/null @@ -1,55 +0,0 @@ -import * as fs from "fs"; - -import { computeProgramDiffs, loadReports } from "../src/report"; -import { DiffBrillig, DiffCircuit } from "../src/types"; - -const srcContent = fs.readFileSync("tests/mocks/gas_report.2.json", "utf8"); -const cmpContent = fs.readFileSync("tests/mocks/gas_report.1.json", "utf8"); - -describe("Program diffs", () => { - const srcProgramReports = loadReports(srcContent).programs; - const cmpProgramReports = loadReports(cmpContent).programs; - - it("should diff 1 and 2 successfully", () => { - const expectedDiffCircuits: DiffCircuit[] = [ - { - name: "c", - opcodes: { previous: 2, current: 4, delta: 2, percentage: 100 }, - circuit_size: { previous: 2, current: 8, delta: 6, percentage: 300 }, - }, - { - name: "d", - opcodes: { previous: 3, current: 4, delta: 1, percentage: 33.333333333333336 }, - circuit_size: { previous: 5, current: 8, delta: 3, percentage: 60 }, - }, - { - name: "b", - opcodes: { previous: 5, current: 4, delta: -1, percentage: -20 }, - circuit_size: { previous: 10, current: 8, delta: -2, percentage: -20 }, - }, - ]; - - const expectedDiffBrilligs: DiffBrillig[] = [ - { - name: "c", - opcodes: { previous: 2, current: 4, delta: 2, percentage: 100 }, - }, - { - name: "d", - opcodes: { previous: 3, current: 4, delta: 1, percentage: 33.333333333333336 }, - }, - { - name: "b", - opcodes: { previous: 5, current: 4, delta: -1, percentage: -20 }, - }, - ]; - - const expectedDiff = [expectedDiffCircuits, expectedDiffBrilligs]; - - expect(computeProgramDiffs(srcProgramReports, cmpProgramReports)).toStrictEqual(expectedDiff); - }); - - it("should return zero diff for identical reports", () => { - expect(computeProgramDiffs(srcProgramReports, srcProgramReports)).toStrictEqual([[], []]); - }); -}); diff --git a/tests/loading.test.ts b/tests/loading.test.ts deleted file mode 100644 index 4f3618d..0000000 --- a/tests/loading.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -import * as fs from "fs"; - -import { loadReports } from "../src/report"; - -const srcContent = fs.readFileSync("tests/mocks/gas_report.2.json", "utf8"); -const cmpContent = fs.readFileSync("tests/mocks/gas_report.1.json", "utf8"); - -describe("Report Loading", () => { - it("should load 1 successfully", () => { - console.log(loadReports(srcContent)); - }); - - it("should load 2 successfully", () => { - console.log(loadReports(cmpContent)); - }); -}); diff --git a/tests/memory_report.test.ts b/tests/memory_report.test.ts new file mode 100644 index 0000000..0184c0b --- /dev/null +++ b/tests/memory_report.test.ts @@ -0,0 +1,26 @@ +import * as fs from "fs"; + +import { memoryReports, formatMemoryReport, computeMemoryDiff } from "../src/report"; + +const srcContent = fs.readFileSync("tests/mocks/mem_report.json", "utf8"); +const ref_1_Content = fs.readFileSync("tests/mocks/1-1-mem_report.json", "utf8"); +const ref_2_Content = fs.readFileSync("tests/mocks/1-2-mem_report.json", "utf8"); + +const memReports = memoryReports(srcContent); + +describe("Markdown format", () => { + it("should generate markdown format", () => { + expect(memReports.length).toBeGreaterThan(0); + const markdown = formatMemoryReport(memReports); + expect(markdown.length).toBeGreaterThan(0); + }); + + it("should generate diff report format", () => { + const ref_1_Reports = memoryReports(ref_1_Content); + const ref_2_Reports = memoryReports(ref_2_Content); + expect(ref_1_Reports.length).toBeGreaterThan(0); + expect(ref_1_Reports.length).toBe(ref_2_Reports.length); + const markdown = computeMemoryDiff(ref_1_Reports, ref_2_Reports); + expect(markdown.length).toBeGreaterThan(0); + }); +}); diff --git a/tests/mocks/1-1-mem_report.json b/tests/mocks/1-1-mem_report.json new file mode 100644 index 0000000..c5d09c2 --- /dev/null +++ b/tests/mocks/1-1-mem_report.json @@ -0,0 +1,16 @@ +{"memory_reports": [ + { + "artifact_name":"keccak256", + "peak_memory":"85.19M" + } + , + { + "artifact_name":"workspace", + "peak_memory":"123.04M" + } + , + { + "artifact_name":"regression_4709", + "peak_memory":"349.30M" + } +]} \ No newline at end of file diff --git a/tests/mocks/1-2-mem_report.json b/tests/mocks/1-2-mem_report.json new file mode 100644 index 0000000..da0d914 --- /dev/null +++ b/tests/mocks/1-2-mem_report.json @@ -0,0 +1,16 @@ +{"memory_reports": [ + { + "artifact_name":"keccak256", + "peak_memory":"95.19M" + } + , + { + "artifact_name":"workspace", + "peak_memory":"103.04M" + } + , + { + "artifact_name":"regression_4709", + "peak_memory":"749.30M" + } +]} \ No newline at end of file diff --git a/tests/mocks/mem_report.json b/tests/mocks/mem_report.json new file mode 100644 index 0000000..6715774 --- /dev/null +++ b/tests/mocks/mem_report.json @@ -0,0 +1,338 @@ +{ + "memory_reports": [ + { + "artifact_name":"1327_concrete_in_generic", + "peak_memory":78.51 + } + , + { + "artifact_name":"1_mul", + "peak_memory":132.60 + } + , + { + "artifact_name":"2_div", + "peak_memory":78.45 + } + , + { + "artifact_name":"3_add", + "peak_memory":78.43 + } + , + { + "artifact_name":"4_sub", + "peak_memory":78.43 + } + , + { + "artifact_name":"5_over", + "peak_memory":78.44 + } + , + { + "artifact_name":"6", + "peak_memory":80.70 + } + , + { + "artifact_name":"6_array", + "peak_memory":78.82 + } + , + { + "artifact_name":"7", + "peak_memory":78.45 + } + , + { + "artifact_name":"7_function", + "peak_memory":78.89 + } + , + { + "artifact_name":"acir_inside_brillig_recursion", + "peak_memory":78.44 + } + , + { + "artifact_name":"aes128_encrypt", + "peak_memory":78.68 + } + , + { + "artifact_name":"arithmetic_binary_operations", + "peak_memory":78.44 + } + , + { + "artifact_name":"array_dynamic", + "peak_memory":78.57 + } + , + { + "artifact_name":"array_dynamic_blackbox_input", + "peak_memory":86.68 + } + , + { + "artifact_name":"array_dynamic_main_output", + "peak_memory":78.43 + } + , + { + "artifact_name":"array_dynamic_nested_blackbox_input", + "peak_memory":80.22 + } + , + { + "artifact_name":"array_eq", + "peak_memory":78.43 + } + , + { + "artifact_name":"array_if_cond_simple", + "peak_memory":78.47 + } + , + { + "artifact_name":"array_len", + "peak_memory":78.50 + } + , + { + "artifact_name":"array_neq", + "peak_memory":78.52 + } + , + { + "artifact_name":"array_sort", + "peak_memory":78.60 + } + , + { + "artifact_name":"array_to_slice", + "peak_memory":78.66 + } + , + { + "artifact_name":"array_to_slice_constant_length", + "peak_memory":78.43 + } + , + { + "artifact_name":"as_witness", + "peak_memory":78.41 + } + , + { + "artifact_name":"assert", + "peak_memory":78.43 + } + , + { + "artifact_name":"assert_statement", + "peak_memory":78.42 + } + , + { + "artifact_name":"assign_ex", + "peak_memory":78.45 + } + , + { + "artifact_name":"bench_ecdsa_secp256k1", + "peak_memory":78.48 + } + , + { + "artifact_name":"bigint", + "peak_memory":81.40 + } + , + { + "artifact_name":"binary_operator_overloading", + "peak_memory":79.03 + } + , + { + "artifact_name":"bit_and", + "peak_memory":78.47 + } + , + { + "artifact_name":"bit_not", + "peak_memory":78.42 + } + , + { + "artifact_name":"bit_shifts_comptime", + "peak_memory":78.49 + } + , + { + "artifact_name":"bit_shifts_runtime", + "peak_memory":79.50 + } + , + { + "artifact_name":"blake3", + "peak_memory":78.45 + } + , + { + "artifact_name":"bool_not", + "peak_memory":78.41 + } + , + { + "artifact_name":"bool_or", + "peak_memory":78.42 + } + , + { + "artifact_name":"break_and_continue", + "peak_memory":78.44 + } + , + { + "artifact_name":"brillig_acir_as_brillig", + "peak_memory":78.54 + } + , + { + "artifact_name":"brillig_arrays", + "peak_memory":78.51 + } + , + { + "artifact_name":"brillig_blake2s", + "peak_memory":78.48 + } + , + { + "artifact_name":"brillig_block_parameter_liveness", + "peak_memory":98.25 + } + , + { + "artifact_name":"brillig_calls", + "peak_memory":78.59 + } + , + { + "artifact_name":"brillig_calls_array", + "peak_memory":78.55 + } + , + { + "artifact_name":"brillig_calls_conditionals", + "peak_memory":78.49 + } + , + { + "artifact_name":"brillig_conditional", + "peak_memory":78.44 + } + , + { + "artifact_name":"brillig_constant_reference_regression", + "peak_memory":78.45 + } + , + { + "artifact_name":"brillig_cow", + "peak_memory":78.59 + } + , + { + "artifact_name":"brillig_cow_assign", + "peak_memory":78.47 + } + , + { + "artifact_name":"brillig_cow_regression", + "peak_memory":79.76 + } + , + { + "artifact_name":"brillig_fns_as_values", + "peak_memory":78.55 + } + , + { + "artifact_name":"brillig_identity_function", + "peak_memory":78.51 + } + , + { + "artifact_name":"brillig_loop_size_regression", + "peak_memory":78.45 + } + , + { + "artifact_name":"brillig_nested_arrays", + "peak_memory":78.67 + } + , + { + "artifact_name":"brillig_not", + "peak_memory":78.45 + } + , + { + "artifact_name":"brillig_oracle", + "peak_memory":78.57 + } + , + { + "artifact_name":"brillig_pedersen", + "peak_memory":78.65 + } + , + { + "artifact_name":"brillig_rc_regression_6123", + "peak_memory":78.56 + } + , + { + "artifact_name":"brillig_recursion", + "peak_memory":78.45 + } + , + { + "artifact_name":"brillig_uninitialized_arrays", + "peak_memory":78.45 + } + , + { + "artifact_name":"cast_and_shift_global", + "peak_memory":78.42 + } + , + { + "artifact_name":"cast_bool", + "peak_memory":78.42 + } + , + { + "artifact_name":"check_large_field_bits", + "peak_memory":78.55 + } + , + { + "artifact_name":"closures_mut_ref", + "peak_memory":78.49 + } + , + { + "artifact_name":"comptime_println", + "peak_memory":78.44 + } + , + { + "artifact_name":"comptime_slice_equality", + "peak_memory":78.41 + } +] +} \ No newline at end of file diff --git a/tests/program_report.test.ts b/tests/program_report.test.ts deleted file mode 100644 index b8b1578..0000000 --- a/tests/program_report.test.ts +++ /dev/null @@ -1,196 +0,0 @@ -import * as fs from "fs"; - -import { - formatBrilligRows, - formatCircuitRows, - formatMarkdownDiff, - formatShellBrilligRows, - formatShellCircuitRows, - formatShellDiff, - formatShellDiffBrillig, -} from "../src/format/program"; -import { computeProgramDiffs, loadReports } from "../src/report"; - -const srcContent = fs.readFileSync("tests/mocks/gas_report.2.json", "utf8"); -const cmpContent = fs.readFileSync("tests/mocks/gas_report.1.json", "utf8"); - -const srcContractReports = loadReports(srcContent).programs; -const cmpContractReports = loadReports(cmpContent).programs; - -describe("Markdown format", () => { - // shows how the runner will run a javascript action with env / stdout protocol - // it("should run action", () => { - // const np = process.execPath; - // const ip = path.join(__dirname, "..", "dist", "index.js"); - // console.log( - // cp - // .execFileSync(np, [ip], { - // env: { - // ...process.env, - // INPUT_WORKFLOWID: "test", - // INPUT_BASE: "base", - // INPUT_HEAD: "head", - // GITHUB_TOKEN: "token", - // INPUT_REPORT: "report", - // }, - // }) - // .toString() - // ); - // }); - - it("should compare 1 to 2 with markdown format", () => { - const [circuitDiffs, brilligDiffs] = computeProgramDiffs( - srcContractReports, - cmpContractReports - ); - expect(circuitDiffs.length).toBeGreaterThan(0); - - const [summaryRows, fullReportRows] = formatCircuitRows(circuitDiffs, 0.8); - fs.writeFileSync( - "tests/mocks/1-2-program-acir.md", - formatMarkdownDiff( - "# Changes to gas cost", - "Rubilmax/foundry-gas-diff", - "d62d23148ca73df77cd4378ee1b3c17f1f303dbf", - summaryRows, - fullReportRows, - true, - false, - undefined, - 0.8 - ) - ); - - const [summaryRowsBrillig, fullReportRowsBrillig] = formatBrilligRows(brilligDiffs, 0.8); - fs.writeFileSync( - "tests/mocks/1-2-program-brillig.md", - formatMarkdownDiff( - "# Changes to gas cost", - "Rubilmax/foundry-gas-diff", - "d62d23148ca73df77cd4378ee1b3c17f1f303dbf", - summaryRowsBrillig, - fullReportRowsBrillig, - false, - false, - undefined, - 0.8 - ) - ); - }); - - it("should compare 1 to 1 with markdown format", () => { - const [circuitDiffs, brilligDiffs] = computeProgramDiffs( - srcContractReports, - srcContractReports - ); - expect(circuitDiffs.length).toBe(0); - - const [summaryRows, fullReportRows] = formatCircuitRows(circuitDiffs, 0.8); - fs.writeFileSync( - "tests/mocks/1-1-program-acir.md", - formatMarkdownDiff( - "# Changes to gas cost", - "Rubilmax/foundry-gas-diff", - "d62d23148ca73df77cd4378ee1b3c17f1f303dbf", - summaryRows, - fullReportRows, - true, - false - ) - ); - - const [summaryRowsBrillig, fullReportRowsBrillig] = formatBrilligRows(brilligDiffs, 0.8); - fs.writeFileSync( - "tests/mocks/1-1-program-brillig.md", - formatMarkdownDiff( - "# Changes to gas cost", - "Rubilmax/foundry-gas-diff", - "d62d23148ca73df77cd4378ee1b3c17f1f303dbf", - summaryRowsBrillig, - fullReportRowsBrillig, - false, - false, - undefined, - 0.8 - ) - ); - }); -}); - -describe("Shell format", () => { - it("should compare 1 to 1", () => { - const [circuitDiffs, brilligDiffs] = computeProgramDiffs( - srcContractReports, - srcContractReports - ); - expect(circuitDiffs.length).toBe(0); - - const [summaryRows, fullReportRows] = formatShellCircuitRows(circuitDiffs); - console.log(formatShellDiff(circuitDiffs, summaryRows, fullReportRows)); - - const [summaryRowsBrillig, fullReportRowsBrillig] = formatShellBrilligRows(brilligDiffs); - console.log( - formatShellDiffBrillig(brilligDiffs, summaryRowsBrillig, fullReportRowsBrillig, false) - ); - }); - - it("should compare 1 to 2", () => { - const [circuitDiffs, brilligDiffs] = computeProgramDiffs( - srcContractReports, - cmpContractReports - ); - expect(circuitDiffs.length).toBeGreaterThan(0); - - const [summaryRows, fullReportRows] = formatShellCircuitRows(circuitDiffs); - console.log(formatShellDiff(circuitDiffs, summaryRows, fullReportRows)); - - const [summaryRowsBrillig, fullReportRowsBrillig] = formatShellBrilligRows(brilligDiffs); - console.log( - formatShellDiffBrillig(brilligDiffs, summaryRowsBrillig, fullReportRowsBrillig, false) - ); - }); - - // This test is just to make sure that we are accurately resetting our reference - // report in case it gets malformed - it("should compare fresh report", () => { - const srcContractReports = cmpContractReports.map((program) => { - const circuitReport = { name: "main", opcodes: 1, circuit_size: 1 }; - const unconstrainedReport = { name: "main", opcodes: 1 }; - const programReport = { - package_name: program.package_name, - functions: [circuitReport], - unconstrained_functions: [unconstrainedReport], - }; - return programReport; - }); - const [circuitDiffs, brilligDiffs] = computeProgramDiffs( - srcContractReports, - cmpContractReports - ); - expect(circuitDiffs.length).toBeGreaterThan(0); - - const [summaryRows, fullReportRows] = formatShellCircuitRows(circuitDiffs); - console.log(formatShellDiff(circuitDiffs, summaryRows, fullReportRows)); - - const [summaryRowsBrillig, fullReportRowsBrillig] = formatShellBrilligRows(brilligDiffs); - console.log( - formatShellDiffBrillig(brilligDiffs, summaryRowsBrillig, fullReportRowsBrillig, false) - ); - }); - - it("should compare 2 to 1", () => { - const [circuitDiffs, brilligDiffs] = computeProgramDiffs( - cmpContractReports, - srcContractReports - ); - expect(circuitDiffs.length).toBeGreaterThan(0); - - const [summaryRows, fullReportRows] = formatShellCircuitRows(circuitDiffs); - console.log(formatShellDiff(circuitDiffs, summaryRows, fullReportRows)); - - const [summaryRowsBrillig, fullReportRowsBrillig] = formatShellBrilligRows(brilligDiffs); - console.log( - formatShellDiffBrillig(brilligDiffs, summaryRowsBrillig, fullReportRowsBrillig, false) - ); - }); -});