Merge pull request #1485 from balena-io/sysinfo-refactor

Refactor system information filtering
This commit is contained in:
bulldozer-balena[bot] 2020-10-12 15:26:56 +00:00 committed by GitHub
commit 27f8872672
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 109 additions and 38 deletions

View File

@ -122,38 +122,10 @@ const getStateDiff = (): DeviceStatus => {
.value(),
};
const shouldReportSysInfo = (type: string, past: number, now: number) => {
if (!past) {
return true;
}
// TODO: Deduplicate this code
switch (type) {
case 'cpu_usage':
// The bucket size of cpu usage is 20
return Math.floor(past / 20) !== Math.floor(now / 20);
case 'cpu_temp':
return Math.floor(past / 5) !== Math.floor(now / 5);
case 'memory_usage':
return Math.floor(past / 10) !== Math.floor(now / 10);
}
return true;
};
const toOmit: string[] = [];
_.each(diff.local, (value, key) => {
// if we have some system information that has changed, we check that it's
// within a certain range before reporting
if (
!shouldReportSysInfo(
key,
(lastReportedLocal as any)[key],
value as number,
)
) {
toOmit.push(key);
}
});
const toOmit: string[] = sysInfo.filterNonSignificantChanges(
lastReportedLocal as sysInfo.SystemInfo,
stateForReport.local as sysInfo.SystemInfo,
);
diff.local = _.omit(diff.local, toOmit);
return _.omitBy(diff, _.isEmpty);
};

View File

@ -1,8 +1,9 @@
import * as systeminformation from 'systeminformation';
import * as osUtils from 'os-utils';
import * as _ from 'lodash';
import { fs, child_process } from 'mz';
export function getCpuUsage() {
export function getCpuUsage(): Promise<number> {
return new Promise((resolve) => {
osUtils.cpuUsage((percent) => {
resolve(Math.round(percent * 100));
@ -11,7 +12,11 @@ export function getCpuUsage() {
}
const blockDeviceRegex = /(\/dev\/.*)p\d+/;
export async function getStorageInfo() {
export async function getStorageInfo(): Promise<{
blockDevice: string;
storageUsed?: number;
storageTotal?: number;
}> {
const fsInfo = await systeminformation.fsSize();
let mainFs: string | undefined;
let total = 0;
@ -51,7 +56,10 @@ export async function getStorageInfo() {
};
}
export async function getMemoryInformation() {
export async function getMemoryInformation(): Promise<{
used: number;
total: number;
}> {
const mem = await systeminformation.mem();
return {
used: bytesToMb(mem.used),
@ -59,11 +67,11 @@ export async function getMemoryInformation() {
};
}
export async function getCpuTemp() {
export async function getCpuTemp(): Promise<number> {
return Math.round((await systeminformation.cpuTemperature()).main);
}
export async function getCpuId() {
export async function getCpuId(): Promise<string | undefined> {
// Read /proc/device-tree/serial-number
// if it's not there, return undefined
try {
@ -76,7 +84,7 @@ export async function getCpuId() {
}
const undervoltageRegex = /under.*voltage/;
export async function undervoltageDetected() {
export async function undervoltageDetected(): Promise<boolean> {
try {
const [dmesgStdout] = await child_process.exec('dmesg');
return undervoltageRegex.test(dmesgStdout.toString());
@ -107,6 +115,39 @@ export async function getSysInfoToReport() {
is_undervolted: undervoltage,
};
}
export type SystemInfo = UnwrappedPromise<
ReturnType<typeof getSysInfoToReport>
>;
const significantChange: { [key in keyof SystemInfo]?: number } = {
cpu_usage: 20,
cpu_temp: 5,
memory_usage: 10,
};
export function filterNonSignificantChanges(
past: Partial<SystemInfo>,
current: SystemInfo,
): Array<keyof SystemInfo> {
return Object.keys(
_.omitBy(current, (value, key: keyof SystemInfo) => {
// If we didn't have a value for this in the past, include it
if (past[key] == null) {
return true;
}
const bucketSize = significantChange[key];
// If we don't have any requirements on this value, include it
if (bucketSize == null) {
return true;
}
return (
Math.floor((value as number) / bucketSize) !==
Math.floor((past[key] as number) / bucketSize)
);
}),
) as Array<keyof SystemInfo>;
}
function bytesToMb(bytes: number) {
return Math.floor(bytes / 1024 / 1024);

58
test/38-sys-info.spec.ts Normal file
View File

@ -0,0 +1,58 @@
import { expect } from 'chai';
import * as sysInfo from '../src/lib/system-info';
describe('System information', () => {
describe('Delta-based filtering', () => {
it('should correctly filter cpu usage', () => {
expect(
sysInfo.filterNonSignificantChanges({ cpu_usage: 21 }, {
cpu_usage: 20,
} as sysInfo.SystemInfo),
).to.deep.equal(['cpu_usage']);
expect(
sysInfo.filterNonSignificantChanges({ cpu_usage: 10 }, {
cpu_usage: 20,
} as sysInfo.SystemInfo),
).to.deep.equal([]);
});
it('should correctly filter cpu temperature', () => {
expect(
sysInfo.filterNonSignificantChanges({ cpu_temp: 21 }, {
cpu_temp: 22,
} as sysInfo.SystemInfo),
).to.deep.equal(['cpu_temp']);
expect(
sysInfo.filterNonSignificantChanges({ cpu_temp: 10 }, {
cpu_temp: 20,
} as sysInfo.SystemInfo),
).to.deep.equal([]);
});
it('should correctly filter memory usage', () => {
expect(
sysInfo.filterNonSignificantChanges({ memory_usage: 21 }, {
memory_usage: 22,
} as sysInfo.SystemInfo),
).to.deep.equal(['memory_usage']);
expect(
sysInfo.filterNonSignificantChanges({ memory_usage: 10 }, {
memory_usage: 20,
} as sysInfo.SystemInfo),
).to.deep.equal([]);
});
it('should not filter if we didnt have a past value', () => {
expect(
sysInfo.filterNonSignificantChanges({}, {
memory_usage: 22,
cpu_usage: 10,
cpu_temp: 5,
} as sysInfo.SystemInfo),
).to.deep.equal([]);
});
});
});