Skip to content

Instantly share code, notes, and snippets.

@qinghon
Last active April 15, 2025 08:35
Show Gist options
  • Save qinghon/89d3422bee924c2a76b3aaa770815129 to your computer and use it in GitHub Desktop.
Save qinghon/89d3422bee924c2a76b3aaa770815129 to your computer and use it in GitHub Desktop.
rust real-time tracking of the impact of code modification on the final binary on size during development
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>Function Size Monitor</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
<style>
.chart-container {
margin: 5px 0;
padding: inherit;
border: 1px solid #ddd;
border-radius: 4px;
width: 500px;
}
.chart-title {
margin-bottom: 10px;
font-family: monospace;
}
.container {
display: flex;
flex-wrap: wrap; /* 允许换行 */
gap: 10px; /* 项目之间的间距 */
}
.item {
flex: 1; /* 项目自动扩展填充空间 */
/*min-width: 200px; !* 设置最小宽度,决定每行显示多少个 *!*/
/* 其他样式... */
}
</style>
</head>
<body>
<div id="chart-list" class="container"></div>
<script>
const MAX_HISTORY = 10;
let currentHash = '';
// 数据获取与存储
async function checkUpdate() {
try {
const res = await fetch(`size_data.json?_=${Date.now()}`);
const newData = await res.json();
const ts = newData['timestamp'];
newData['timestamp'] = '';
const newHash = await digestMessage(JSON.stringify(newData));
newData['timestamp'] = ts;
if (newHash !== currentHash) {
currentHash = newHash;
storeHistory(newData);
renderCharts();
}
} catch (err) {
console.error('Error:', err);
}
}
// SHA-256哈希生成
async function digestMessage(message) {
const encoder = new TextEncoder();
const data = encoder.encode(message);
const hashBuffer = await crypto.subtle.digest('SHA-1', data);
return Array.from(new Uint8Array(hashBuffer))
.map(b => b.toString(16).padStart(2, '0')).join('');
}
// 历史数据存储
function storeHistory(data) {
const history = JSON.parse(localStorage.getItem('sizeHistory') || '[]');
history.push({
timestamp: data.timestamp,
fileSize: data['file-size'],
textSectionSize: data['text-section-size'],
functions: data.functions.reduce((acc, f) => {
acc[f.name] = f.size;
return acc;
}, {})
});
if (history.length > MAX_HISTORY) {
history.splice(0, history.length - MAX_HISTORY);
}
localStorage.setItem('sizeHistory', JSON.stringify(history));
}
// 图表渲染
function renderCharts() {
const history = JSON.parse(localStorage.getItem('sizeHistory') || '[]');
// 清空容器
const container = document.getElementById('chart-list');
container.innerHTML = '';
if (history.length < 2) {
document.getElementById('chart-list').innerHTML = '<p>需要至少两次构建数据才能显示变化</p>';
return;
}
// 渲染总大小图表
if (history.length >= 1) {
const totalWrapper = document.createElement('div');
totalWrapper.className = 'chart-container';
totalWrapper.innerHTML = `
<h3 class="chart-title">总文件大小变化</h3>
<canvas id="chart-total"></canvas>
`;
container.appendChild(totalWrapper);
renderChart(
document.getElementById('chart-total'),
history.map(h => h.timestamp),
history.map(h => h.fileSize),
'Total File Size (bytes)',
['#2196F3', '#FF9800'] // 添加第二个数据集颜色
);
const textWrapper = document.createElement('div');
textWrapper.className = 'chart-container';
textWrapper.innerHTML = `
<h3 class="chart-title">text大小变化</h3>
<canvas id="chart-text"></canvas>
`;
container.appendChild(textWrapper);
renderChart(
document.getElementById('chart-text'),
history.map(h => h.timestamp),
history.map(h => h.textSectionSize),
'Text Size (bytes)',
['#2196F3', '#FF9800'] // 添加第二个数据集颜色
);
}
// 计算变化量
const changes = calculateChanges(history);
const sortedFunctions = Object.keys(changes)
.filter(funcName => hasChanges(funcName, history))
.sort((a, b) => Math.abs(changes[b]) - Math.abs(changes[a]));
// 为每个函数创建图表
sortedFunctions.forEach(funcName => {
const chartId = `chart-${funcName.replace(/[^a-z0-9]/gi, '_')}`;
const wrapper = document.createElement('div');
wrapper.className = 'chart-container';
wrapper.innerHTML = `
<h3 class="chart-title">${funcName}</h3>
<canvas id="${chartId}"></canvas>
`;
container.appendChild(wrapper);
renderChart(
document.getElementById(chartId),
history.map(h => h.timestamp),
history.map(h => h.functions[funcName] || 0),
`Size Changes - ${funcName}`
);
});
}
// 检查函数在历史记录中是否有变化
function hasChanges(funcName, history) {
for (let i = 1; i < history.length; i++) {
const prev = history[i - 1].functions[funcName] || 0;
const curr = history[i].functions[funcName] || 0;
if (prev !== curr) return true;
}
return false;
}
// 计算函数变化量
function calculateChanges(history) {
const latest = history[history.length - 1].functions;
const prev = history[history.length - 2].functions;
return Object.keys(latest).reduce((acc, name) => {
acc[name] = latest[name] - (prev[name] || 0);
return acc;
}, {});
}
// 单个图表渲染逻辑
function renderChart(canvas, labels, data, title, colors = ['#4CAF50']) {
const datasets = Array.isArray(data[0]) ?
data.map((d, i) => ({
label: title + ' ' + (i + 1),
data: d,
borderColor: colors[i % colors.length],
})) : [{
label: title,
data,
borderColor: colors[0],
datalabels: {
display: true,
}
}];
new Chart(canvas, {
type: 'line',
data: {
labels,
datasets
},
options: {
transitions: {
show: {
animations: {
x: {from: 0 },
y: {from: 0 }
}
},
hide: {
animations: {
x: {to: 0},
y: {to: 0 }
}
}
},
responsive: true,
scales: {
y: {
beginAtZero: false,
title: {display: true, text: 'B'}
}
},
plugins: {
title: {display: true, text: title},
datalabels: {
display: true,
formatter: (value) => {
return value
},
}
}
}
});
}
// 每2秒检查更新
setInterval(checkUpdate, 2000);
checkUpdate();
</script>
</body>
</html>
#!/bin/bash
mkdir -p build
python3 -m http.server --directory build &
export RUSTFLAGS="-Zlocation-detail=none -Zfmt-debug=none -Cstrip=none"
cargo watch --ignore "${BUILD_DIR}" -x check \
-s 'echo "{\"timestamp\": \"$(date -u +"%H:%M:%SZ")\"}" > build/metadata.json' \
-s 'cargo +nightly bloat -Z build-std=std,panic_abort -Z build-std-features="optimize_for_size" -Z build-std-features=panic_immediate_abort -Z unstable-options --release --message-format=json -n 0 | jq -s add build/metadata.json - > build/size_data.json' \
-s 'rm build/metadata.json'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment