UNPKG

@eagleoutice/flowr-dev

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

219 lines 8.16 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.countSignatureDatabase = countSignatureDatabase; /** * Counts what the signature database mounted on the benchmarking machine carries, so a release also shows * how the database grew. Everything is read from the manifests and the bundle headers, i.e. without unpacking * a bundle, the one exception being the small base-R bundle whose entries are walked for {@link SigDbBaseCounts}. * @module */ const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const manifest_1 = require("../../project/sigdb/manifest"); const decompress_1 = require("../../project/sigdb/decompress"); const index_format_1 = require("../../project/sigdb/index-format"); const reader_1 = require("../../project/sigdb/reader"); const schema_1 = require("../../project/sigdb/schema"); /** what a temporal tier of a bundle keeps, in the words the wiki uses for it */ const KindOfTier = { current: 'latest only', full: 'full history', history: 'older only' }; const ManifestFile = /\.manifest\.json(\.(br|zst|gz))?$/; function sizeOf(file) { try { return fs_1.default.statSync(file).size; } catch { return 0; } } async function contentOf(file) { try { return (await (0, decompress_1.readHeaderOf)(file))?.content; } catch { return undefined; } } /** the kind a shard belongs to, falling back to its tier so an unknown tier still gets a counter of its own */ function kindOf(tier) { const name = String(tier ?? 'unknown'); return KindOfTier[name] ?? name; } function add(into, key, value) { into[key] = (into[key] ?? 0) + value; } /** * Every distinct shard of every discovered bundle, plus the dictionaries and manifests they need. A shard id a * later manifest ships again is skipped (the two copies hold the same packages), and with it that manifest's * dictionary, so nothing is counted twice. */ function collectBundles(paths) { const bundles = []; const seen = new Set(); let dictionaries = 0; let manifests = 0; for (const p of paths) { if (!ManifestFile.test(p)) { // a standalone bundle, which is a database of one shard without a manifest around it const id = path_1.default.basename(p); if (!seen.has(id)) { seen.add(id); bundles.push({ id, ref: { id, tier: 'full', path: p, hash: '', packages: 0, versions: 0 }, file: p, manifest: undefined }); } continue; } let manifest; try { manifest = (0, manifest_1.readManifestFile)(p); } catch (e) { console.log(` skipping signature database manifest ${p}: ${e.message}`); continue; } const baseDir = path_1.default.dirname(p); const own = (manifest.shards ?? []).filter(s => s?.id !== undefined && !seen.has(s.id)); if (own.length === 0) { continue; } for (const ref of own) { seen.add(ref.id); bundles.push({ id: ref.id, ref, file: (0, decompress_1.resolveSource)(baseDir, ref.path), manifest }); } manifests += sizeOf(p); for (const dict of manifest.dicts ?? []) { dictionaries += sizeOf((0, decompress_1.resolveSource)(baseDir, dict.path)); } } return { bundles, dictionaries, manifests }; } /** every package name the bundles route, so the same package in several bundles is only counted once */ function countPackages(bundles) { const names = new Set(); for (const { ref, manifest } of bundles) { for (const name of Object.keys(ref.idx?.p ?? {})) { names.add(name); } for (const name of Object.keys(manifest?.meta ?? {})) { names.add(name); } } return names.size > 0 ? names.size : Math.max(0, ...bundles.map(b => b.ref.packages ?? 0)); } /** * Walk the base-R bundle of the newest R release and count what its function records carry. It is a few * hundred KiB unpacked, so this stays in the milliseconds; only the numeric tuples are read, no string * dictionary is needed for them. */ async function countBaseEntries(bundles) { const base = bundles.find(b => b.ref.tier === 'current' && b.id.startsWith('base')); if (base === undefined) { return undefined; } let db; try { db = await reader_1.SigDatabase.open(base.file, { hash: base.ref.hash, index: base.ref.idx ? (0, index_format_1.decodeIndex)(base.ref.idx, base.manifest?.meta) : undefined }); const carrying = { 'with parameters': 0, 'with a call graph': 0, 'with a source location': 0, 'with a help topic': 0 }; for (const name of Object.values(schema_1.FnPropNames)) { carrying[name] = 0; } let functions = 0; let parameters = 0; for (const blob of db.allBlobs()) { for (const fn of blob.fns ?? []) { functions++; const [, sigIdx, cgIdx, props, fileIdx] = fn; if (sigIdx >= 0) { carrying['with parameters']++; parameters += blob.sigs[sigIdx]?.length ?? 0; } if (cgIdx >= 0) { carrying['with a call graph']++; } if (fileIdx >= 0) { carrying['with a source location']++; } if (fn.length > 6) { carrying['with a help topic']++; } for (const [bit, name] of Object.entries(schema_1.FnPropNames)) { if ((props & Number(bit)) !== 0) { carrying[name]++; } } } } return { functions, parameters, functionsCarrying: carrying }; } catch (e) { console.log(` skipping the signature database entry breakdown: ${e.message}`); return undefined; } finally { db?.close(); } } /** * Counts the bundles of the mounted signature database, what they describe, and what they occupy. * Every step is defensive, as this also runs against older databases when the history is filled in, and a * machine without a mounted database simply yields `undefined` instead of failing the benchmark. */ async function countSignatureDatabase() { let paths; try { paths = (0, manifest_1.defaultSigDbPaths)(); } catch (e) { console.log(` no signature database counted: ${e.message}`); return undefined; } const { bundles, dictionaries, manifests } = collectBundles(paths); if (bundles.length === 0) { console.log(' no signature database is mounted, its counters are left out'); return undefined; } const bundlesByKind = {}; const functionsByKind = {}; const sizeByKind = {}; let packageVersions = 0; let functions = 0; let size = dictionaries + manifests; for (const bundle of bundles) { const content = await contentOf(bundle.file); const kind = kindOf(content?.tier ?? bundle.ref.tier); const bytes = sizeOf(bundle.file); add(bundlesByKind, kind, 1); add(functionsByKind, kind, content?.functions ?? 0); add(sizeByKind, kind, bytes); packageVersions += content?.versions ?? bundle.ref.versions ?? 0; functions += content?.functions ?? 0; size += bytes; } return { bundles: bundles.length, bundlesByKind, packages: countPackages(bundles), packageVersions, functions, functionsByKind, sizeByKind, sizeOfDictionaries: dictionaries, sizeOfManifests: manifests, size, base: await countBaseEntries(bundles) }; } //# sourceMappingURL=sigdb-counts.js.map