inspectorProfiler.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. const tslib_1 = require("tslib");
  4. const configuration_1 = require("../configuration");
  5. const serviceManager_1 = require("../serviceManager");
  6. const miscellaneous_1 = require("../utils/miscellaneous");
  7. const Debug = require("debug");
  8. const semver = require("semver");
  9. class CurrentProfile {
  10. }
  11. class InspectorProfiler {
  12. constructor() {
  13. this.profiler = undefined;
  14. this.currentProfile = null;
  15. this.logger = Debug('axm:features:profiling:inspector');
  16. this.isNode11 = semver.satisfies(semver.clean(process.version), '>11.x');
  17. }
  18. init() {
  19. this.profiler = serviceManager_1.ServiceManager.get('inspector');
  20. if (this.profiler === undefined) {
  21. configuration_1.default.configureModule({
  22. heapdump: false,
  23. 'feature.profiler.heap_snapshot': false,
  24. 'feature.profiler.heap_sampling': false,
  25. 'feature.profiler.cpu_js': false
  26. });
  27. return console.error(`Failed to require the profiler via inspector, disabling profiling ...`);
  28. }
  29. this.profiler.getSession().post('Profiler.enable');
  30. this.profiler.getSession().post('HeapProfiler.enable');
  31. this.logger('init');
  32. this.actionService = serviceManager_1.ServiceManager.get('actions');
  33. if (this.actionService === undefined) {
  34. return this.logger(`Fail to get action service`);
  35. }
  36. this.transport = serviceManager_1.ServiceManager.get('transport');
  37. if (this.transport === undefined) {
  38. return this.logger(`Fail to get transport service`);
  39. }
  40. configuration_1.default.configureModule({
  41. heapdump: true,
  42. 'feature.profiler.heapsnapshot': !this.isNode11,
  43. 'feature.profiler.heapsampling': true,
  44. 'feature.profiler.cpu_js': true
  45. });
  46. this.register();
  47. }
  48. register() {
  49. if (this.actionService === undefined) {
  50. return this.logger(`Fail to get action service`);
  51. }
  52. this.logger('register');
  53. this.actionService.registerAction('km:heapdump', this.onHeapdump.bind(this));
  54. this.actionService.registerAction('km:cpu:profiling:start', this.onCPUProfileStart.bind(this));
  55. this.actionService.registerAction('km:cpu:profiling:stop', this.onCPUProfileStop.bind(this));
  56. this.actionService.registerAction('km:heap:sampling:start', this.onHeapProfileStart.bind(this));
  57. this.actionService.registerAction('km:heap:sampling:stop', this.onHeapProfileStop.bind(this));
  58. }
  59. destroy() {
  60. this.logger('Inspector Profiler destroyed !');
  61. if (this.profiler === undefined)
  62. return;
  63. this.profiler.getSession().post('Profiler.disable');
  64. this.profiler.getSession().post('HeapProfiler.disable');
  65. }
  66. onHeapProfileStart(opts, cb) {
  67. if (typeof cb !== 'function') {
  68. cb = opts;
  69. opts = {};
  70. }
  71. if (typeof opts !== 'object' || opts === null) {
  72. opts = {};
  73. }
  74. if (this.profiler === undefined) {
  75. return cb({
  76. err: 'Profiler not available',
  77. success: false
  78. });
  79. }
  80. if (this.currentProfile !== null) {
  81. return cb({
  82. err: 'A profiling is already running',
  83. success: false
  84. });
  85. }
  86. this.currentProfile = new CurrentProfile();
  87. this.currentProfile.uuid = miscellaneous_1.default.generateUUID();
  88. this.currentProfile.startTime = Date.now();
  89. this.currentProfile.initiated = typeof opts.initiated === 'string'
  90. ? opts.initiated : 'manual';
  91. cb({ success: true, uuid: this.currentProfile.uuid });
  92. const defaultSamplingInterval = 16384;
  93. this.profiler.getSession().post('HeapProfiler.startSampling', {
  94. samplingInterval: typeof opts.samplingInterval === 'number'
  95. ? opts.samplingInterval : defaultSamplingInterval
  96. });
  97. if (isNaN(parseInt(opts.timeout, 10)))
  98. return;
  99. const duration = parseInt(opts.timeout, 10);
  100. setTimeout(_ => {
  101. this.onHeapProfileStop(_ => {
  102. return;
  103. });
  104. }, duration);
  105. }
  106. onHeapProfileStop(cb) {
  107. if (this.currentProfile === null) {
  108. return cb({
  109. err: 'No profiling are already running',
  110. success: false
  111. });
  112. }
  113. if (this.profiler === undefined) {
  114. return cb({
  115. err: 'Profiler not available',
  116. success: false
  117. });
  118. }
  119. cb({ success: true, uuid: this.currentProfile.uuid });
  120. this.profiler.getSession().post('HeapProfiler.stopSampling', (_, { profile }) => {
  121. if (this.currentProfile === null)
  122. return;
  123. if (this.transport === undefined)
  124. return;
  125. const data = JSON.stringify(profile);
  126. this.transport.send('profilings', {
  127. uuid: this.currentProfile.uuid,
  128. duration: Date.now() - this.currentProfile.startTime,
  129. at: this.currentProfile.startTime,
  130. data,
  131. success: true,
  132. initiated: this.currentProfile.initiated,
  133. type: 'heapprofile',
  134. heapprofile: true
  135. });
  136. this.currentProfile = null;
  137. });
  138. }
  139. onCPUProfileStart(opts, cb) {
  140. if (typeof cb !== 'function') {
  141. cb = opts;
  142. opts = {};
  143. }
  144. if (typeof opts !== 'object' || opts === null) {
  145. opts = {};
  146. }
  147. if (this.profiler === undefined) {
  148. return cb({
  149. err: 'Profiler not available',
  150. success: false
  151. });
  152. }
  153. if (this.currentProfile !== null) {
  154. return cb({
  155. err: 'A profiling is already running',
  156. success: false
  157. });
  158. }
  159. this.currentProfile = new CurrentProfile();
  160. this.currentProfile.uuid = miscellaneous_1.default.generateUUID();
  161. this.currentProfile.startTime = Date.now();
  162. this.currentProfile.initiated = typeof opts.initiated === 'string'
  163. ? opts.initiated : 'manual';
  164. cb({ success: true, uuid: this.currentProfile.uuid });
  165. if (process.hasOwnProperty('_startProfilerIdleNotifier') === true) {
  166. process._startProfilerIdleNotifier();
  167. }
  168. this.profiler.getSession().post('Profiler.start');
  169. if (isNaN(parseInt(opts.timeout, 10)))
  170. return;
  171. const duration = parseInt(opts.timeout, 10);
  172. setTimeout(_ => {
  173. this.onCPUProfileStop(_ => {
  174. return;
  175. });
  176. }, duration);
  177. }
  178. onCPUProfileStop(cb) {
  179. if (this.currentProfile === null) {
  180. return cb({
  181. err: 'No profiling are already running',
  182. success: false
  183. });
  184. }
  185. if (this.profiler === undefined) {
  186. return cb({
  187. err: 'Profiler not available',
  188. success: false
  189. });
  190. }
  191. cb({ success: true, uuid: this.currentProfile.uuid });
  192. if (process.hasOwnProperty('_stopProfilerIdleNotifier') === true) {
  193. process._stopProfilerIdleNotifier();
  194. }
  195. this.profiler.getSession().post('Profiler.stop', (_, res) => {
  196. if (this.currentProfile === null)
  197. return;
  198. if (this.transport === undefined)
  199. return;
  200. const profile = res.profile;
  201. const data = JSON.stringify(profile);
  202. this.transport.send('profilings', {
  203. uuid: this.currentProfile.uuid,
  204. duration: Date.now() - this.currentProfile.startTime,
  205. at: this.currentProfile.startTime,
  206. data,
  207. success: true,
  208. initiated: this.currentProfile.initiated,
  209. type: 'cpuprofile',
  210. cpuprofile: true
  211. });
  212. this.currentProfile = null;
  213. });
  214. }
  215. onHeapdump(opts, cb) {
  216. if (typeof cb !== 'function') {
  217. cb = opts;
  218. opts = {};
  219. }
  220. if (typeof opts !== 'object' || opts === null) {
  221. opts = {};
  222. }
  223. if (this.profiler === undefined) {
  224. return cb({
  225. err: 'Profiler not available',
  226. success: false
  227. });
  228. }
  229. cb({ success: true });
  230. setTimeout(() => {
  231. const startTime = Date.now();
  232. this.takeSnapshot()
  233. .then(data => {
  234. return this.transport.send('profilings', {
  235. data,
  236. at: startTime,
  237. initiated: typeof opts.initiated === 'string' ? opts.initiated : 'manual',
  238. duration: Date.now() - startTime,
  239. type: 'heapdump'
  240. });
  241. }).catch(err => {
  242. return cb({
  243. success: err.message,
  244. err: err
  245. });
  246. });
  247. }, 200);
  248. }
  249. takeSnapshot() {
  250. return new Promise((resolve, reject) => tslib_1.__awaiter(this, void 0, void 0, function* () {
  251. if (this.profiler === undefined)
  252. return reject(new Error(`Profiler not available`));
  253. const chunks = [];
  254. const chunkHandler = (raw) => {
  255. const data = raw.params;
  256. chunks.push(data.chunk);
  257. };
  258. this.profiler.getSession().on('HeapProfiler.addHeapSnapshotChunk', chunkHandler);
  259. yield this.profiler.getSession().post('HeapProfiler.takeHeapSnapshot', {
  260. reportProgress: false
  261. });
  262. this.profiler.getSession().removeListener('HeapProfiler.addHeapSnapshotChunk', chunkHandler);
  263. return resolve(chunks.join(''));
  264. }));
  265. }
  266. }
  267. exports.default = InspectorProfiler;
  268. //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5zcGVjdG9yUHJvZmlsZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcHJvZmlsZXJzL2luc3BlY3RvclByb2ZpbGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUVBLG9EQUE0QztBQUM1QyxzREFBa0Q7QUFHbEQsMERBQThDO0FBRzlDLCtCQUE4QjtBQUM5QixpQ0FBZ0M7QUFFaEMsTUFBTSxjQUFjO0NBSW5CO0FBRUQsTUFBcUIsaUJBQWlCO0lBQXRDO1FBRVUsYUFBUSxHQUFpQyxTQUFTLENBQUE7UUFHbEQsbUJBQWMsR0FBMEIsSUFBSSxDQUFBO1FBQzVDLFdBQU0sR0FBYSxLQUFLLENBQUMsa0NBQWtDLENBQUMsQ0FBQTtRQUM1RCxhQUFRLEdBQVksTUFBTSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRSxPQUFPLENBQUMsQ0FBQTtJQWdUdEYsQ0FBQztJQTlTQyxJQUFJO1FBQ0YsSUFBSSxDQUFDLFFBQVEsR0FBRywrQkFBYyxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBQTtRQUMvQyxJQUFJLElBQUksQ0FBQyxRQUFRLEtBQUssU0FBUyxFQUFFO1lBQy9CLHVCQUFhLENBQUMsZUFBZSxDQUFDO2dCQUM1QixRQUFRLEVBQUUsS0FBSztnQkFDZixnQ0FBZ0MsRUFBRSxLQUFLO2dCQUN2QyxnQ0FBZ0MsRUFBRSxLQUFLO2dCQUN2Qyx5QkFBeUIsRUFBRSxLQUFLO2FBQ2pDLENBQUMsQ0FBQTtZQUNGLE9BQU8sT0FBTyxDQUFDLEtBQUssQ0FBQyx1RUFBdUUsQ0FBQyxDQUFBO1NBQzlGO1FBRUQsSUFBSSxDQUFDLFFBQVEsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsQ0FBQTtRQUNsRCxJQUFJLENBQUMsUUFBUSxDQUFDLFVBQVUsRUFBRSxDQUFDLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxDQUFBO1FBQ3RE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