{"version":3,"file":"tools/tool-env/profile.js.map","mappings":"AAAAA;AAAAC,SAAgB;AAAhB;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA,MAAMC,KAAK,GAAGC,OAAO,CAAC,QAAD,CAArB;;AAEA,MAAMC,MAAM,GAAGC,UAAU,CAACC,OAAO,CAACC,GAAR,CAAYC,cAAZ,IAA8B,KAA/B,CAAzB,C,CAAgE;;AAQhE,IAAIC,WAAW,GAA0BC,MAAM,CAACC,MAAP,CAAc,IAAd,CAAzC;AAEA,IAAIC,UAAU,GAAG,GAAjB,C,CACA;;AACA,SAASC,MAAT,CAAgBC,GAAhB,EAA2B;AACzB,SAAOF,UAAU,CAACG,MAAX,GAAoBD,GAA3B,EAAgC;AAC9BF,cAAU,GAAGA,UAAU,GAAGA,UAA1B;AACD;;AACD,SAAOA,UAAU,CAAC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","names":["module","Profile","Fiber","require","filter","parseFloat","process","env","METEOR_PROFILE","bucketStats","Object","create","SPACES_STR","spaces","len","length","slice","DOTS_STR","dots","leftRightAlign","str1","str2","middle","Math","max","leftRightDots","printIndentation","isLastLeafStack","init","i","isLastLeaf","last","formatMs","n","String","round","replace","encodeEntryKey","entry","join","decodeEntryKey","key","split","globalEntry","running","bucketName","f","enabled","assign","profileWrapper","apply","arguments","name","currentEntry","current","profilerEntry","push","start","hrtime","elapsed","stats","time","count","isOther","pop","bucket","run","console","log","runningName","print","reportNum","report","setupReport","reportHierarchy","reportHotLeaves","getTopLevelTotal","entries","prefix","entryName","entryStats","entryTime","isTopLevelEntry","topLevelEntries","text","isChild","entry1","entry2","children","hasChildren","hasSignificantChildren","some","isLeaf","otherTime","total","forEach","child","injectOtherTime","other","reportOn","isParent","childrenList","concat","allLeafs","set","map","keys","sort","leafTotals","leafName","leaf","totals","info","a","b","topTotal","parent"],"sourceRoot":"","sources":["tools/tool-env/profile.ts"],"sourcesContent":["// Tiny profiler\n//\n// Enable by setting the environment variable `METEOR_PROFILE`.\n//\n// The main entry point is `Profile`, which wraps an existing function\n// and returns a new function which, when called, calls the original\n// function and profiles it.\n//\n// before:\n//\n// foo: function (a) {\n// return a + this.b;\n// },\n//\n// after:\n//\n// foo: Profile(\"foo\", function (a) {\n// return a + this.b;\n// }),\n//\n// The advantage of this form is that it doesn't change the\n// indentation of the wrapped code, which makes merging changes from\n// other code branches easier.\n//\n// If profiling is disabled (if `METEOR_PROFILE` isn't set), `Profile`\n// simply returns the original function.\n//\n// To run a profiling session and print the report, call `Profile.run`:\n//\n// var createBundle = function () {\n// Profile.run(\"bundle\", function () {\n// ...code to create the bundle which includes calls to `Profile`.\n// });\n// };\n//\n// Code is not profiled when called outside of a `Profile.run`, so the\n// times in the report only include the time spent inside of the call\n// to `Profile.run`.\n//\n// Sometimes you'll want to use a name for the profile bucket which\n// depends on the arguments passed to the function or the value of\n// `this`. In this case you can pass a function for the bucket\n// argument, which will be called to get the bucket name.\n//\n// before:\n// build: function (target) {\n// ... build target ...\n// },\n//\n// after:\n// build: Profile(\n// function (target) { return \"build \" + target; },\n// function (target) {\n// ... build target ...\n// }),\n//\n// But if it's easier, you can use `Profile.time` instead, which\n// immediately calls the passed function with no arguments and\n// profiles it, and returns what the function returns.\n//\n// foo: function (a) {\n// var self = this;\n// return Profile.time(\"foo\", function () {\n// return a + self.b;\n// });\n// },\n//\n// build: function (target) {\n// var self = this;\n// self.doSomeSetup();\n// Profile.time(\"build \" + target, function () {\n// ... build target ...\n// });\n// self.doSomeCleanup();\n// },\n//\n// The disadvantage is that you end up changing the indentation of the\n// profiled code, which makes merging branches more painful. But you\n// can profile anywhere in the code; you don't have to just profile at\n// function boundaries.\n//\n// Note profiling code will itself add a bit of execution time.\n// If you profile in a tight loop and your total execution time is\n// going up, you're probably starting to profile how long it takes to\n// profile things :).\n//\n// If another profile (such as \"compile js\") is called while the first\n// function is currently being profiled, this creates an entry like\n// this:\n//\n// build client : compile js\n//\n// which can continue to be nested, e.g.,\n//\n// build client : compile js : read source files\n//\n// The total time reported for a bucket such as \"build client\" doesn't\n// change regardless of whether it has child entries or not. However,\n// if an entry has child entries, it automatically gets an \"other\"\n// entry:\n//\n// build client: 400.0\n// compile js: 300.0\n// read source files: 20.0\n// other compile js: 280.0\n// other build client: 100.0\n//\n// The \"other\" entry reports how much time was spent in the \"build\n// client\" entry not spent in the other child entries.\n//\n// The are two reports displayed: the hierarchical report and the\n// leaf time report. The hierarchical report looks like the example\n// above and shows how much time was spent in each entry within its\n// parent entry.\n//\n// The primary purpose of the hierarchical report is to be able to see\n// where times are unaccounted for. If you see a lot of time being\n// spent in an \"other\" bucket, and you don't know what it is, you can\n// add more profiling to dig deeper.\n//\n// The leaf time report shows the total time spent within leaf\n// buckets. For example, if if multiple steps have \"read source\n// files\", the leaf time reports shows the total amount of time spent\n// in \"read source files\" across all calls.\n//\n// Once you see in the hierarchical report that you have a good handle\n// on accounting for most of the time, the leaf report shows you which\n// buckets are the most expensive.\n//\n// By only including leaf buckets, the times in the leaf report are\n// non-overlapping. (The total of the times equals the elapsed time\n// being profiled).\n//\n// For example, suppose \"A\" is profiled for a total time of 200ms, and\n// that includes a call to \"B\" of 150ms:\n//\n// B: 150\n// A (without B): 50\n//\n// and suppose there's another call to \"A\" which *doesn't* include a\n// call to \"B\":\n//\n// A: 300\n//\n// and there's a call to \"B\" directly:\n//\n// B: 100\n//\n// All for a total time of 600ms. In the hierarchical report, this\n// looks like:\n//\n// A: 500.0\n// B: 150.0\n// other A: 350.0\n// B: 100.0\n//\n// and in the leaf time report:\n//\n// other A: 350.0\n// B: 250.0\n//\n// In both reports the grand total is 600ms.\n\nconst Fiber = require('fibers');\n\nconst filter = parseFloat(process.env.METEOR_PROFILE || \"100\"); // ms\n\ntype Stats = {\n time: number;\n count: number;\n isOther: boolean;\n}\n\nlet bucketStats: Record = Object.create(null);\n\nlet SPACES_STR = ' ';\n// return a string of `x` spaces\nfunction spaces(len: number) {\n while (SPACES_STR.length < len) {\n SPACES_STR = SPACES_STR + SPACES_STR;\n }\n return SPACES_STR.slice(0, len);\n}\n\nlet DOTS_STR = '.';\n// return a string of `x` dots\nfunction dots(len: number) {\n while (DOTS_STR.length < len) {\n DOTS_STR = DOTS_STR + DOTS_STR;\n }\n return DOTS_STR.slice(0, len);\n}\n\nfunction leftRightAlign(str1: string, str2: string, len: number) {\n var middle = Math.max(1, len - str1.length - str2.length);\n return str1 + spaces(middle) + str2;\n}\n\nfunction leftRightDots(str1: string, str2: string, len: number) {\n var middle = Math.max(1, len - str1.length - str2.length);\n return str1 + dots(middle) + str2;\n}\n\nfunction printIndentation(isLastLeafStack: boolean[]) {\n if (!isLastLeafStack.length) {\n return '';\n }\n\n const { length } = isLastLeafStack;\n let init = '';\n for (let i = 0; i < length - 1; ++i) {\n const isLastLeaf = isLastLeafStack[i];\n init += isLastLeaf ? ' ' : '│ ';\n }\n\n const last = isLastLeafStack[length - 1] ? '└─ ' : '├─ ';\n\n return init + last;\n}\n\nfunction formatMs(n: number) {\n // integer with thousands separators\n return String(Math.round(n)).replace(/\\B(?=(\\d{3})+(?!\\d))/g, \",\") + \" ms\";\n}\n\nfunction encodeEntryKey(entry: string[]) {\n return entry.join('\\t');\n}\n\nfunction decodeEntryKey(key: string) {\n return key.split('\\t');\n}\n\nconst globalEntry: string[] = [];\nlet running = false;\n\nexport function Profile<\n TArgs extends any[],\n TResult,\n>(\n bucketName: string | ((...args: TArgs) => string),\n f: (...args: TArgs) => TResult,\n): typeof f {\n if (! Profile.enabled) {\n return f;\n }\n\n return Object.assign(function profileWrapper(this: any) {\n if (! running) {\n return f.apply(this, arguments as any);\n }\n\n const name = typeof bucketName === \"function\"\n ? bucketName.apply(this, arguments as any)\n : bucketName;\n\n const currentEntry = Fiber.current\n ? Fiber.current.profilerEntry || (Fiber.current.profilerEntry = [])\n : globalEntry;\n\n currentEntry.push(name);\n const key = encodeEntryKey(currentEntry);\n const start = process.hrtime();\n try {\n return f.apply(this, arguments as any);\n } finally {\n const elapsed = process.hrtime(start);\n const stats = (bucketStats[key] || (bucketStats[key] = {\n time: 0.0,\n count: 0,\n isOther: false,\n }));\n stats.time += (elapsed[0] * 1000 + elapsed[1] / 1000000);\n stats.count++;\n currentEntry.pop();\n }\n }, f) as typeof f;\n}\n\nexport namespace Profile {\n export let enabled = !! process.env.METEOR_PROFILE;\n\n export function time(bucket: string, f: () => TResult) {\n return Profile(bucket, f)();\n }\n\n export function run(bucket: string, f: () => TResult) {\n if (! Profile.enabled) {\n return f();\n }\n\n if (running) {\n // We've kept the calls to Profile.run in the tool disjoint so far,\n // and should probably keep doing so, but if we mess up, warn and continue.\n console.log(\"Warning: Nested Profile.run at \" + bucket);\n return time(bucket, f);\n }\n\n runningName = bucket;\n print(`(#${reportNum}) Profiling: ${runningName}`);\n start();\n try {\n return time(bucket, f);\n } finally {\n report();\n reportNum++;\n }\n }\n\n function start() {\n bucketStats = {};\n running = true;\n }\n\n let runningName: string;\n let reportNum = 1;\n function report() {\n if (! Profile.enabled) {\n return;\n }\n running = false;\n print('');\n setupReport();\n reportHierarchy();\n print('');\n reportHotLeaves();\n print('');\n print(`(#${reportNum}) Total: ${formatMs(getTopLevelTotal())}` +\n ` (${runningName})`);\n print('');\n }\n}\n\ntype Entry = string[];\nlet entries: Entry[] = [];\n\nconst prefix = \"| \";\n\nfunction entryName(entry: Entry) {\n return entry[entry.length - 1];\n}\n\nfunction entryStats(entry: Entry) {\n return bucketStats[encodeEntryKey(entry)];\n}\n\nfunction entryTime(entry: Entry) {\n return entryStats(entry).time;\n}\n\nfunction isTopLevelEntry(entry: Entry) {\n return entry.length === 1;\n}\n\nfunction topLevelEntries() {\n return entries.filter(isTopLevelEntry);\n}\n\nfunction print(text: string) {\n console.log(prefix + text);\n}\n\nfunction isChild(entry1: Entry, entry2: Entry) {\n if (entry2.length !== entry1.length + 1) {\n return false;\n }\n for (var i = entry1.length - 1; i >= 0; i--) {\n if (entry1[i] !== entry2[i]) {\n return false;\n }\n }\n return true;\n}\n\nfunction children(entry1: Entry) {\n return entries.filter(entry2 => isChild(entry1, entry2));\n}\n\nfunction hasChildren(entry: Entry) {\n return children(entry).length > 0;\n}\n\nfunction hasSignificantChildren(entry: Entry) {\n return children(entry).some(entry => entryTime(entry) >= filter);\n}\n\nfunction isLeaf(entry: Entry) {\n return ! hasChildren(entry);\n}\n\nfunction otherTime(entry: Entry) {\n let total = 0;\n children(entry).forEach(child => {\n total += entryTime(child);\n });\n return entryTime(entry) - total;\n}\n\nfunction injectOtherTime(entry: Entry) {\n const other: Entry = entry.slice(0);\n other.push(\"other \" + entryName(entry));\n bucketStats[encodeEntryKey(other)] = {\n time: otherTime(entry),\n count: entryStats(entry).count,\n isOther: true\n };\n entries.push(other);\n};\n\nfunction reportOn(entry: Entry, isLastLeafStack: boolean[] = []) {\n const stats = entryStats(entry);\n const isParent = hasSignificantChildren(entry);\n const name = entryName(entry);\n\n print((isParent ? leftRightDots : leftRightAlign)\n (printIndentation(isLastLeafStack) + name, formatMs(stats.time), 70)\n + (stats.isOther ? \"\" : (\" (\" + stats.count + \")\")));\n\n if (isParent) {\n const childrenList = children(entry).filter(entry => {\n return entryStats(entry).time > filter;\n });\n childrenList.forEach((child, i) => {\n const isLastLeaf = i === childrenList.length - 1;\n reportOn(child, isLastLeafStack.concat(isLastLeaf));\n });\n }\n}\n\nfunction reportHierarchy() {\n topLevelEntries().forEach(entry => reportOn(entry));\n}\n\nfunction allLeafs() {\n const set: { [name: string]: any } = Object.create(null);\n entries.filter(isLeaf).map(entryName).forEach(name => set[name] = true);\n return Object.keys(set).sort();\n}\n\nfunction leafTotals(leafName: string) {\n let time = 0;\n let count = 0;\n\n entries.filter(entry => {\n return entryName(entry) === leafName && isLeaf(entry);\n }).forEach(leaf => {\n const stats = entryStats(leaf);\n time += stats.time;\n count += stats.count;\n });\n\n return { time, count };\n}\n\nfunction reportHotLeaves() {\n print('Top leaves:');\n\n const totals = allLeafs().map(leaf => {\n const info = leafTotals(leaf);\n return {\n name: leaf,\n time: info.time,\n count: info.count,\n };\n }).sort((a, b) => {\n return a.time === b.time ? 0 : a.time > b.time ? -1 : 1;\n });\n\n totals.forEach(total => {\n if (total.time < 100) { // hard-coded larger filter to quality as \"hot\" here\n return;\n }\n print(leftRightDots(total.name, formatMs(total.time), 65) + ` (${total.count})`);\n });\n}\n\nfunction getTopLevelTotal() {\n let topTotal = 0;\n topLevelEntries().forEach(entry => {\n topTotal += entryTime(entry);\n });\n return topTotal;\n}\n\nfunction setupReport() {\n entries = Object.keys(bucketStats).map(decodeEntryKey);\n entries.filter(hasSignificantChildren).forEach(parent => {\n injectOtherTime(parent);\n });\n}\n"]}