Compare commits

..

No commits in common. "c69dd1efb288d410b55c98753f9725eb8cfdd1fa" and "ef528ccb3f3181d8f0c5e3b7203e936c4b54e1fc" have entirely different histories.

4 changed files with 51 additions and 44 deletions

View File

@ -124,14 +124,12 @@ public:
auto err auto err
= ::bind(socket, (struct sockaddr*)&address, sizeof(address)); = ::bind(socket, (struct sockaddr*)&address, sizeof(address));
if (err < 0) { if (err < 0) {
close(socket);
return Err { .msg = std::format("could not bind ({})", err) }; return Err { .msg = std::format("could not bind ({})", err) };
}; };
} }
{ {
auto err = ::listen(socket, 0); auto err = ::listen(socket, 0);
if (err < 0) { if (err < 0) {
close(socket);
return Err { .msg = std::format("could not listen ({})", err) }; return Err { .msg = std::format("could not listen ({})", err) };
} }
} }
@ -142,7 +140,6 @@ public:
int client = ::accept( int client = ::accept(
socket, (struct sockaddr*)&client_address, &address_size); socket, (struct sockaddr*)&client_address, &address_size);
if (client < 0) { if (client < 0) {
close(socket);
return Err { .msg return Err { .msg
= std::format("could not accept ({})", client) }; = std::format("could not accept ({})", client) };
} }
@ -152,7 +149,10 @@ public:
std::string message = {}; std::string message = {};
while (true) { while (true) {
ssize_t bytes_read = read(client, buffer, buf_len); ssize_t bytes_read = read(client, buffer, buf_len);
if (bytes_read <= 0) { if (bytes_read < 0) {
return Err { .msg
= std::format("could not read ({})", bytes_read) };
} else if (bytes_read == 0) {
break; break;
} }
for (size_t i = 0; i < (size_t)bytes_read; ++i) { for (size_t i = 0; i < (size_t)bytes_read; ++i) {
@ -168,7 +168,6 @@ public:
"error parsing rpc message: '{}' @ {}:{}\n", "error parsing rpc message: '{}' @ {}:{}\n",
err.msg, err.pos.line, err.pos.col); err.msg, err.pos.line, err.pos.col);
close(client); close(client);
close(socket);
return Err { return Err {
.msg = msg, .msg = msg,
}; };

View File

@ -5,16 +5,28 @@ export type FlameGraphNode = {
children: FlameGraphNode[]; children: FlameGraphNode[];
}; };
export async function flameGraphData(): Promise<FlameGraphNode> { export function flameGraphData(): FlameGraphNode {
return await fetch("/api/flame-graph") return JSON.parse(
.then((v) => v.json()) `{"fn":0,"acc":257,"parent":0,"children":[{"fn":18,"acc":251,"parent":0,"children":[{"fn":12,"acc":30,"parent":1,"children":[]}]}]}`,
.then((v) => v.flameGraph); );
} }
export async function codeData(): Promise<string> { export function codeData() {
return await fetch("/api/source") return `\
.then((v) => v.json()) fn add(a, b) {
.then((v) => v.text); + a b
}
let result = 0;
let i = 0;
loop {
if >= i 10 {
break;
}
result = add(result, 5);
i = + i 1;
}
`;
} }
export type CodeCovEntry = { export type CodeCovEntry = {
@ -24,8 +36,8 @@ export type CodeCovEntry = {
covers: number; covers: number;
}; };
export async function codeCoverageData(): Promise<CodeCovEntry[]> { export function codeCoverageData(): CodeCovEntry[] {
return await fetch("/api/code-coverage") return JSON.parse(
.then((v) => v.json()) `[{"index":0,"line":1,"col":1,"covers":2},{"index":28,"line":5,"col":1,"covers":1},{"index":44,"line":6,"col":1,"covers":1},{"index":55,"line":7,"col":1,"covers":1},{"index":66,"line":8,"col":5,"covers":11},{"index":104,"line":11,"col":5,"covers":10},{"index":19,"line":2,"col":5,"covers":10},{"index":133,"line":12,"col":5,"covers":10},{"index":87,"line":9,"col":9,"covers":1}]`,
.then((v) => v.codeCoveragea); );
} }

View File

@ -1,16 +1,22 @@
import * as data from "./data.ts"; import {
CodeCovEntry,
codeCoverageData,
codeData,
flameGraphData,
FlameGraphNode,
} from "./data.ts";
function loadCodeCoverage( function loadCodeCoverage(
text: string, text: string,
data: data.CodeCovEntry[], data: CodeCovEntry[],
container: HTMLPreElement, container: HTMLPreElement,
tooltip: HTMLElement, tooltip: HTMLElement,
) { ) {
const entries = data.toSorted(( const entries = data.toSorted((
a: data.CodeCovEntry, a: CodeCovEntry,
b: data.CodeCovEntry, b: CodeCovEntry,
) => b.index - a.index); ) => b.index - a.index);
const charEntries: { [key: string]: data.CodeCovEntry } = {}; const charEntries: { [key: string]: CodeCovEntry } = {};
const elements: HTMLElement[] = []; const elements: HTMLElement[] = [];
let line = 1; let line = 1;
let col = 1; let col = 1;
@ -91,7 +97,7 @@ function loadCodeCoverage(
type FlameGraphFnNames = { [key: number]: string }; type FlameGraphFnNames = { [key: number]: string };
function loadFlameGraph( function loadFlameGraph(
flameGraphData: data.FlameGraphNode, flameGraphData: FlameGraphNode,
fnNames: FlameGraphFnNames, fnNames: FlameGraphFnNames,
flameGraphDiv: HTMLDivElement, flameGraphDiv: HTMLDivElement,
) { ) {
@ -121,10 +127,10 @@ function loadFlameGraph(
const nodes: Node[] = []; const nodes: Node[] = [];
function calculateNodeRects( function calculateNodeRects(
node: data.FlameGraphNode, node: FlameGraphNode,
depth: number, depth: number,
totalAcc: data.FlameGraphNode["acc"], totalAcc: FlameGraphNode["acc"],
offsetAcc: data.FlameGraphNode["acc"], offsetAcc: FlameGraphNode["acc"],
) { ) {
const x = (offsetAcc / totalAcc) * canvas.width; const x = (offsetAcc / totalAcc) * canvas.width;
const y = canvas.height - 30 * depth - 30; const y = canvas.height - 30 * depth - 30;
@ -188,7 +194,7 @@ function loadFlameGraph(
}); });
} }
async function main() { function main() {
type RenderFns = { type RenderFns = {
"source-code": () => void; "source-code": () => void;
"code-coverage": () => void; "code-coverage": () => void;
@ -218,18 +224,14 @@ async function main() {
return lineElement; return lineElement;
} }
const codeData = await data.codeData();
const codeCoverageData = await data.codeCoverageData();
const flameGraphData = await data.flameGraphData();
const view = document.querySelector("#view")!; const view = document.querySelector("#view")!;
const renderFunctions: RenderFns = { const renderFunctions: RenderFns = {
"source-code": () => { "source-code": () => {
const container = document.createElement("div"); const container = document.createElement("div");
container.classList.add("code-container"); container.classList.add("code-container");
const lines = createLineElement(codeData); const lines = createLineElement(codeData());
const code = document.createElement("pre"); const code = document.createElement("pre");
code.innerText = codeData; code.innerText = codeData();
container.append(lines, code); container.append(lines, code);
view.replaceChildren(container); view.replaceChildren(container);
}, },
@ -240,13 +242,8 @@ async function main() {
tooltip.id = "covers-tooltip"; tooltip.id = "covers-tooltip";
tooltip.hidden = true; tooltip.hidden = true;
const code = document.createElement("pre"); const code = document.createElement("pre");
loadCodeCoverage( loadCodeCoverage(codeData(), codeCoverageData(), code, tooltip);
codeData, const lines = createLineElement(codeData());
codeCoverageData,
code,
tooltip,
);
const lines = createLineElement(codeData);
container.append(lines, code); container.append(lines, code);
const view = document.querySelector("#view")!; const view = document.querySelector("#view")!;
view.replaceChildren(container, tooltip); view.replaceChildren(container, tooltip);
@ -255,7 +252,7 @@ async function main() {
const container = document.createElement("div"); const container = document.createElement("div");
const view = document.querySelector("#view")!; const view = document.querySelector("#view")!;
view.replaceChildren(container); view.replaceChildren(container);
loadFlameGraph(flameGraphData, { loadFlameGraph(flameGraphData(), {
0: "<entry>", 0: "<entry>",
12: "add", 12: "add",
18: "main", 18: "main",

View File

@ -27,9 +27,8 @@ export class RuntimeConnection {
while (true) { while (true) {
const buf = new Uint8Array(256); const buf = new Uint8Array(256);
const readRes = await this.connection.read(buf); const readRes = await this.connection.read(buf);
if (readRes != null) { result += new TextDecoder().decode(buf);
result += new TextDecoder().decode(buf.slice(0, readRes)); if (readRes == null) {
} else {
break; break;
} }
} }