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 2952x 42x 2910x 2910x 42671x 2910x 2910x 42671x 5898x 2910x 1906x 1004x 1906x 104088x 104088x 65321x 1906x 1906x 27547x 1906x 1906x 1906x 9684895x 9684895x 9684895x 9684895x 46276x 46276x 1906x 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 9025028x 9025028x 9025028x 98450766x 98450766x 98450766x 8730012x 89720754x 15366616x 74354138x 295016x | 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;
}
|