Prioritize Unused Chromium Includes #319
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Prioritize Unused Chromium Includes | |
| on: | |
| workflow_dispatch: | |
| schedule: | |
| - cron: '0 18 * * *' | |
| permissions: {} | |
| jobs: | |
| prioritized_by_added_size: | |
| name: Prioritized by added size | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| with: | |
| repository: dsanders11/chromium-include-cleanup | |
| - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 | |
| with: | |
| python-version: '3.12' | |
| cache: 'pip' | |
| - name: Install Dependencies | |
| run: pip install -r requirements.txt | |
| - name: Download Unused Includes Output | |
| run: | | |
| curl https://gist.githubusercontent.com/dsanders11/ccf3505dcbb35492cbadade1ceb663b6/raw/unused-includes.csv > unused-includes.csv | |
| - name: Download Include Analysis Output | |
| run: | | |
| curl https://commondatastorage.googleapis.com/chromium-browser-clang/include-analysis.js > include-analysis.js | |
| - name: Find Priority Unused Includes | |
| run: | | |
| python set_edge_weights.py unused-includes.csv include-analysis.js --config chromium > weighted-unused-includes.csv | |
| python filter_include_changes.py weighted-unused-includes.csv --config chromium --filter-third-party --no-filter-mojom-headers --weight-threshold 10000000 > priority-unused-includes.csv | |
| python set_edge_weights.py priority-unused-includes.csv include-analysis.js --config chromium --metric expanded_size > priority-unused-includes.expanded_size.csv | |
| python set_edge_weights.py priority-unused-includes.csv include-analysis.js --config chromium --metric prevalence > priority-unused-includes.prevalence.csv | |
| python set_edge_weights.py priority-unused-includes.csv include-analysis.js --config chromium --metric includer_size > priority-unused-includes.includer_size.csv | |
| python set_edge_weights.py priority-unused-includes.csv include-analysis.js --config chromium --metric centrality > priority-unused-includes.centrality.csv | |
| - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 | |
| with: | |
| name: weighted-unused-includes | |
| path: | | |
| weighted-unused-includes.csv | |
| priority-unused-includes.csv | |
| priority-unused-includes.expanded_size.csv | |
| priority-unused-includes.prevalence.csv | |
| priority-unused-includes.includer_size.csv | |
| priority-unused-includes.centrality.csv | |
| - run: npm install @actions/cache | |
| - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 | |
| with: | |
| script: | | |
| const fs = require('node:fs'); | |
| const cache = await import('${{ github.workspace }}/node_modules/@actions/cache/lib/cache.js'); | |
| const data = fs.readFileSync('./priority-unused-includes.csv', 'utf8').trim().split('\n'); | |
| const expandedSizeData = fs.readFileSync('./priority-unused-includes.expanded_size.csv', 'utf8').trim().split('\n'); | |
| const prevalenceData = fs.readFileSync('./priority-unused-includes.prevalence.csv', 'utf8').trim().split('\n'); | |
| const includerSizeData = fs.readFileSync('./priority-unused-includes.includer_size.csv', 'utf8').trim().split('\n'); | |
| const centralityData = fs.readFileSync('./priority-unused-includes.centrality.csv', 'utf8').trim().split('\n'); | |
| let totalAddedSize = 0; | |
| const unusedIncludes = await Promise.all(data.map(async (line, idx) => { | |
| const [,, filename, include, added_size] = line.trim().split(','); | |
| const addedSize = parseInt(added_size); | |
| totalAddedSize += addedSize; | |
| // Check if this is known from a previous run | |
| const cacheKey = `prioritize-unused-chromium-${filename}-${include}`; | |
| const cacheHit = | |
| (await cache.restoreCache(['/dev/null'], cacheKey, undefined, { | |
| lookupOnly: true, | |
| })) !== undefined; | |
| if (!cacheHit) { | |
| // Create a cache entry (only the name matters) to keep track of | |
| // includes we've seen from previous runs to mark them as stale | |
| await cache.saveCache(['/dev/null'], cacheKey); | |
| } | |
| return [ | |
| `${filename} --> ${include.replace(/</g, '<').replace(/>/g, '>')}`, | |
| addedSize, | |
| parseFloat(prevalenceData[idx].trim().split(',')[4]), | |
| parseInt(expandedSizeData[idx].trim().split(',')[4]), | |
| parseInt(includerSizeData[idx].trim().split(',')[4]), | |
| parseFloat(centralityData[idx].trim().split(',')[4]), | |
| cacheHit, | |
| ]; | |
| })); | |
| const addTable = (includes) => { | |
| core.summary.addTable([ | |
| [ | |
| { data: 'Include Edge', header: true }, | |
| { data: 'Added Size', header: true }, | |
| { data: 'Prevalence', header: true }, | |
| { data: 'Expanded Size', header: true }, | |
| { data: 'Includer Size', header: true }, | |
| { data: 'Centrality', header: true }, | |
| ], | |
| // Sort by added size, then convert it back to string or it won't render | |
| ...includes | |
| .sort((a, b) => b[1] - a[1]) | |
| .map(([edge, added_size, prevalence, expandedSize, includerSize, centrality]) => [ | |
| edge, | |
| added_size.toLocaleString(), | |
| `${prevalence.toFixed(2)}%`, | |
| expandedSize.toLocaleString(), | |
| includerSize.toLocaleString(), | |
| centrality.toFixed(5), | |
| ]), | |
| ]); | |
| } | |
| if (unusedIncludes.length > 0) { | |
| core.summary.addHeading('✂️ Priority Unused Chromium Includes'); | |
| core.summary.addRaw(`\n> [!NOTE]\n> These are suggestions from \`clangd\` and are known to contain false positives.\n\n`); | |
| core.summary.addRaw(`Found ${unusedIncludes.length} unused includes over 10 MB of added size for a total of ${totalAddedSize.toLocaleString()} bytes of added size`); | |
| const newlySeen = unusedIncludes.filter(([, , , , , , cacheHit]) => !cacheHit) | |
| if (newlySeen.length > 0) { | |
| core.summary.addHeading('Not Seen Before', '2'); | |
| addTable(newlySeen); | |
| core.summary.addHeading('All Unused Includes', '2'); | |
| } else { | |
| core.summary.addBreak(); | |
| } | |
| addTable(unusedIncludes); | |
| } else { | |
| core.summary.addRaw('🎉 No priority unused Chromium includes'); | |
| } | |
| await core.summary.write(); | |
| prioritized_by_prevalence: | |
| name: Prioritized by prevalence | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| with: | |
| repository: dsanders11/chromium-include-cleanup | |
| - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 | |
| with: | |
| python-version: '3.12' | |
| cache: 'pip' | |
| - name: Install Dependencies | |
| run: pip install -r requirements.txt | |
| - name: Download Unused Includes Output | |
| run: | | |
| curl https://gist.githubusercontent.com/dsanders11/ccf3505dcbb35492cbadade1ceb663b6/raw/unused-includes.csv > unused-includes.csv | |
| - name: Download Include Analysis Output | |
| run: | | |
| curl https://commondatastorage.googleapis.com/chromium-browser-clang/include-analysis.js > include-analysis.js | |
| - name: Find Priority Unused Includes | |
| run: | | |
| python set_edge_weights.py unused-includes.csv include-analysis.js --config chromium --metric prevalence > weighted-unused-includes.csv | |
| python filter_include_changes.py weighted-unused-includes.csv --config chromium --filter-third-party --no-filter-mojom-headers --weight-threshold 5 > priority-unused-includes.prevalence.csv | |
| python set_edge_weights.py priority-unused-includes.prevalence.csv include-analysis.js --config chromium --metric expanded_size > priority-unused-includes.expanded_size.csv | |
| python set_edge_weights.py priority-unused-includes.prevalence.csv include-analysis.js --config chromium --metric input_size > priority-unused-includes.input_size.csv | |
| python set_edge_weights.py priority-unused-includes.prevalence.csv include-analysis.js --config chromium --metric includer_size > priority-unused-includes.includer_size.csv | |
| python set_edge_weights.py priority-unused-includes.prevalence.csv include-analysis.js --config chromium --metric centrality > priority-unused-includes.centrality.csv | |
| - run: npm install @actions/cache | |
| - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 | |
| with: | |
| script: | | |
| const fs = require('node:fs'); | |
| const cache = await import('${{ github.workspace }}/node_modules/@actions/cache/lib/cache.js'); | |
| const addedSizeData = fs.readFileSync('./priority-unused-includes.input_size.csv', 'utf8').trim().split('\n'); | |
| const expandedSizeData = fs.readFileSync('./priority-unused-includes.expanded_size.csv', 'utf8').trim().split('\n'); | |
| const prevalenceData = fs.readFileSync('./priority-unused-includes.prevalence.csv', 'utf8').trim().split('\n'); | |
| const includerSizeData = fs.readFileSync('./priority-unused-includes.includer_size.csv', 'utf8').trim().split('\n'); | |
| const centralityData = fs.readFileSync('./priority-unused-includes.centrality.csv', 'utf8').trim().split('\n'); | |
| const unusedIncludes = await Promise.all(prevalenceData.map(async (line, idx) => { | |
| const [,, filename, include, prevalence] = line.trim().split(','); | |
| // Check if this is known from a previous run | |
| const cacheKey = `prioritize-unused-chromium-${filename}-${include}-prevalence`; | |
| const cacheHit = | |
| (await cache.restoreCache(['/dev/null'], cacheKey, undefined, { | |
| lookupOnly: true, | |
| })) !== undefined; | |
| if (!cacheHit) { | |
| // Create a cache entry (only the name matters) to keep track of | |
| // includes we've seen from previous runs to mark them as stale | |
| await cache.saveCache(['/dev/null'], cacheKey); | |
| } | |
| return [ | |
| `${filename} --> ${include.replace(/</g, '<').replace(/>/g, '>')}`, | |
| parseFloat(prevalence), | |
| parseInt(addedSizeData[idx].trim().split(',')[4]), | |
| parseInt(expandedSizeData[idx].trim().split(',')[4]), | |
| parseInt(includerSizeData[idx].trim().split(',')[4]), | |
| parseFloat(centralityData[idx].trim().split(',')[4]), | |
| cacheHit, | |
| ]; | |
| })); | |
| const addTable = (includes) => { | |
| core.summary.addTable([ | |
| [ | |
| { data: 'Include Edge', header: true }, | |
| { data: 'Prevalence', header: true }, | |
| { data: 'Added Size', header: true }, | |
| { data: 'Expanded Size', header: true }, | |
| { data: 'Includer Size', header: true }, | |
| { data: 'Centrality', header: true }, | |
| ], | |
| // Sort by prevalence, then convert it back to string or it won't render | |
| ...includes | |
| .sort((a, b) => b[1] - a[1]) | |
| .map(([edge, prevalence, added_size, expandedSize, includerSize, centrality]) => [ | |
| edge, | |
| `${prevalence.toFixed(2)}%`, | |
| added_size.toLocaleString(), | |
| expandedSize.toLocaleString(), | |
| includerSize.toLocaleString(), | |
| centrality.toFixed(5), | |
| ]), | |
| ]); | |
| } | |
| if (unusedIncludes.length > 0) { | |
| core.summary.addHeading('✂️ Priority Unused Chromium Includes'); | |
| core.summary.addRaw(`\n> [!NOTE]\n> These are suggestions from \`clangd\` and are known to contain false positives.\n\n`); | |
| core.summary.addRaw(`Found ${unusedIncludes.length} unused includes with over 5% prevalence`); | |
| const newlySeen = unusedIncludes.filter(([, , , , , , cacheHit]) => !cacheHit) | |
| if (newlySeen.length > 0) { | |
| core.summary.addHeading('Not Seen Before', '2'); | |
| addTable(newlySeen); | |
| core.summary.addHeading('All Unused Includes', '2'); | |
| } else { | |
| core.summary.addBreak(); | |
| } | |
| addTable(unusedIncludes); | |
| } else { | |
| core.summary.addRaw('🎉 No priority unused Chromium includes'); | |
| } | |
| await core.summary.write(); | |
| prioritized_by_centrality: | |
| name: Prioritized by centrality | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| with: | |
| repository: dsanders11/chromium-include-cleanup | |
| - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 | |
| with: | |
| python-version: '3.12' | |
| cache: 'pip' | |
| - name: Install Dependencies | |
| run: pip install -r requirements.txt | |
| - name: Download Unused Includes Output | |
| run: | | |
| curl https://gist.githubusercontent.com/dsanders11/ccf3505dcbb35492cbadade1ceb663b6/raw/unused-includes.csv > unused-includes.csv | |
| - name: Download Include Analysis Output | |
| run: | | |
| curl https://commondatastorage.googleapis.com/chromium-browser-clang/include-analysis.js > include-analysis.js | |
| - name: Find Priority Unused Includes | |
| run: | | |
| python set_edge_weights.py unused-includes.csv include-analysis.js --config chromium --metric centrality > weighted-unused-includes.csv | |
| python filter_include_changes.py weighted-unused-includes.csv --config chromium --filter-third-party --no-filter-mojom-headers --weight-threshold 0.005 > priority-unused-includes.centrality.csv | |
| python set_edge_weights.py priority-unused-includes.centrality.csv include-analysis.js --config chromium --metric expanded_size > priority-unused-includes.expanded_size.csv | |
| python set_edge_weights.py priority-unused-includes.centrality.csv include-analysis.js --config chromium --metric input_size > priority-unused-includes.input_size.csv | |
| python set_edge_weights.py priority-unused-includes.centrality.csv include-analysis.js --config chromium --metric includer_size > priority-unused-includes.includer_size.csv | |
| python set_edge_weights.py priority-unused-includes.centrality.csv include-analysis.js --config chromium --metric prevalence > priority-unused-includes.prevalence.csv | |
| - run: npm install @actions/cache | |
| - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 | |
| with: | |
| script: | | |
| const fs = require('node:fs'); | |
| const cache = await import('${{ github.workspace }}/node_modules/@actions/cache/lib/cache.js'); | |
| const addedSizeData = fs.readFileSync('./priority-unused-includes.input_size.csv', 'utf8').trim().split('\n'); | |
| const expandedSizeData = fs.readFileSync('./priority-unused-includes.expanded_size.csv', 'utf8').trim().split('\n'); | |
| const prevalenceData = fs.readFileSync('./priority-unused-includes.prevalence.csv', 'utf8').trim().split('\n'); | |
| const includerSizeData = fs.readFileSync('./priority-unused-includes.includer_size.csv', 'utf8').trim().split('\n'); | |
| const centralityData = fs.readFileSync('./priority-unused-includes.centrality.csv', 'utf8').trim().split('\n'); | |
| const unusedIncludes = await Promise.all(centralityData.map(async (line, idx) => { | |
| const [,, filename, include, centrality] = line.trim().split(','); | |
| // Check if this is known from a previous run | |
| const cacheKey = `prioritize-unused-chromium-${filename}-${include}-centrality`; | |
| const cacheHit = | |
| (await cache.restoreCache(['/dev/null'], cacheKey, undefined, { | |
| lookupOnly: true, | |
| })) !== undefined; | |
| if (!cacheHit) { | |
| // Create a cache entry (only the name matters) to keep track of | |
| // includes we've seen from previous runs to mark them as stale | |
| await cache.saveCache(['/dev/null'], cacheKey); | |
| } | |
| return [ | |
| `${filename} --> ${include.replace(/</g, '<').replace(/>/g, '>')}`, | |
| parseFloat(centrality), | |
| parseInt(addedSizeData[idx].trim().split(',')[4]), | |
| parseFloat(prevalenceData[idx].trim().split(',')[4]), | |
| parseInt(expandedSizeData[idx].trim().split(',')[4]), | |
| parseInt(includerSizeData[idx].trim().split(',')[4]), | |
| cacheHit, | |
| ]; | |
| })); | |
| const addTable = (includes) => { | |
| core.summary.addTable([ | |
| [ | |
| { data: 'Include Edge', header: true }, | |
| { data: 'Centrality', header: true }, | |
| { data: 'Added Size', header: true }, | |
| { data: 'Prevalence', header: true }, | |
| { data: 'Expanded Size', header: true }, | |
| { data: 'Includer Size', header: true }, | |
| ], | |
| // Sort by centrality | |
| ...includes | |
| .sort((a, b) => b[1] - a[1]) | |
| .map(([edge, centrality, added_size, prevalence, expandedSize, includerSize]) => [ | |
| edge, | |
| centrality.toFixed(5), | |
| added_size.toLocaleString(), | |
| `${prevalence.toFixed(2)}%`, | |
| expandedSize.toLocaleString(), | |
| includerSize.toLocaleString(), | |
| ]), | |
| ]); | |
| } | |
| if (unusedIncludes.length > 0) { | |
| core.summary.addHeading('✂️ Priority Unused Chromium Includes'); | |
| core.summary.addRaw(`\n> [!NOTE]\n> These are suggestions from \`clangd\` and are known to contain false positives.\n\n`); | |
| core.summary.addRaw(`Found ${unusedIncludes.length} unused includes with >= 0.005 centrality`); | |
| const newlySeen = unusedIncludes.filter(([, , , , , , cacheHit]) => !cacheHit) | |
| if (newlySeen.length > 0) { | |
| core.summary.addHeading('Not Seen Before', '2'); | |
| addTable(newlySeen); | |
| core.summary.addHeading('All Unused Includes', '2'); | |
| } else { | |
| core.summary.addBreak(); | |
| } | |
| addTable(unusedIncludes); | |
| } else { | |
| core.summary.addRaw('🎉 No priority unused Chromium includes'); | |
| } | |
| await core.summary.write(); |