Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | 54x 2956x 42x 2914x 2914x 42699x 2914x 2914x 42699x 5902x 2914x 1910x 1004x 1910x 104136x 104136x 65333x 1910x 1910x 27575x 1910x 1910x 1910x 9687827x 9687827x 9687827x 9687827x 46304x 46304x 1910x 1004x 1004x 15124x 15044x 15044x 58080x 1004x 1004x 1004x 1004x 1004x 29604x 29604x 27852x 27852x 27852x 5888x 21964x 29604x 30088x 30088x 15044x 15044x 30088x 29604x 1004x 27852x 27852x 41752x 41752x 34200x 27852x 9025317x 9025317x 9025317x 98451028x 98451028x 98451028x 8730107x 89720921x 15366695x 74354226x 295210x | import { type Profiler } from "node:inspector";
type Normalized = { start: number; end: number; count: number };
type RawRange = Normalized & { area: number; order: number };
/** Files larger than this use event sweep to avoid allocating huge hits arrays */
const HITS_ARRAY_MAX_SIZE = 2_000_000;
export function normalize(
scriptCoverage: Pick<Profiler.ScriptCoverage, "functions">,
hitsArrayMaxSize = HITS_ARRAY_MAX_SIZE,
): Normalized[] {
if (scriptCoverage.functions.length === 0) {
return [];
}
let order = 0;
const ranges: RawRange[] = scriptCoverage.functions.flatMap((fn) =>
fn.ranges.map((range) => ({
start: range.startOffset,
end: range.endOffset,
count: range.count,
area: range.endOffset - range.startOffset,
order: order++,
})),
);
let maxEnd = 0;
for (const r of ranges) {
if (r.end > maxEnd) {
maxEnd = r.end;
}
}
if (maxEnd <= hitsArrayMaxSize) {
return normalizeWithHitsArray(ranges, maxEnd);
}
return normalizeWithEventSweep(ranges);
}
function normalizeWithHitsArray(ranges: RawRange[], maxEnd: number): Normalized[] {
// Paint ranges into hits array so that the most specific range is applied last
ranges.sort((a, b) => {
const diff = b.area - a.area;
if (diff !== 0) return diff;
return a.end - b.end;
});
const hits = new Uint32Array(maxEnd);
for (const range of ranges) {
// V8's endOffset is exclusive - the offset at range's end belongs to the parent range
hits.fill(range.count, range.start, range.end);
}
const normalized: Normalized[] = [];
let start = 0;
for (let end = 1; end <= hits.length; end++) {
const isLast = end === hits.length;
const current = isLast ? null : hits[end];
const previous = hits[start];
if (current !== previous || isLast) {
normalized.push({
start,
end: end - 1,
count: previous,
});
start = end;
}
}
return normalized;
}
function normalizeWithEventSweep(ranges: RawRange[]): Normalized[] {
const events: { offset: number; range: RawRange; isStart: boolean }[] = [];
for (const range of ranges) {
if (range.start < range.end) {
events.push({ offset: range.start, range, isStart: true });
events.push({ offset: range.end, range, isStart: false });
}
}
events.sort((a, b) => a.offset - b.offset);
const active: RawRange[] = [];
const normalized: Normalized[] = [];
let cursor = events.length > 0 ? events[0].offset : 0;
let index = 0;
while (index < events.length) {
const offset = events[index].offset;
if (active.length > 0 && cursor < offset) {
const count = getMostSpecificRange(active).count;
const previous = normalized.at(-1);
if (previous && previous.end + 1 === cursor && previous.count === count) {
previous.end = offset - 1;
} else {
normalized.push({ start: cursor, end: offset - 1, count });
}
}
while (index < events.length && events[index].offset === offset) {
const event = events[index];
if (event.isStart) {
active.push(event.range);
} else {
active.splice(active.indexOf(event.range), 1);
}
index++;
}
cursor = offset;
}
return normalized;
}
/** Pick the range that painting would have applied last in `normalizeWithHitsArray` */
function getMostSpecificRange(ranges: RawRange[]): RawRange {
let winner = ranges[0];
for (let index = 1; index < ranges.length; index++) {
const range = ranges[index];
if (
range.area < winner.area ||
(range.area === winner.area && range.end > winner.end) ||
(range.area === winner.area && range.end === winner.end && range.order > winner.order)
) {
winner = range;
}
}
return winner;
}
export function getCount(
offset: Pick<Profiler.CoverageRange, "startOffset" | "endOffset">,
coverages: Normalized[],
) {
let low = 0;
let high = coverages.length - 1;
while (low <= high) {
const mid = Math.floor((low + high) / 2);
const coverage = coverages[mid];
if (coverage.start <= offset.startOffset && offset.startOffset <= coverage.end) {
return coverage.count;
} else if (offset.startOffset < coverage.start) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return 0;
}
|