الواجهات البرمجية لتوقيت الأداء (Performance Timing API)

من موسوعة حسوب

الاستقرار: 1- تجريبي.

تقدم الواجهة البرمجية لتوقيت الأداء تطبيقًا لمواصفات W3C Performance Timeline. الغرض من  الواجهة البرمجية (API) هو دعم مجموعة من مقاييس الأداء عالية الدقة. والتي هي نفس واجهات الأداء المُطبّقة في متصفحات الويب الحديثة.

const { PerformanceObserver, performance } = require('perf_hooks');

const obs = new PerformanceObserver((items) => {
  console.log(items.getEntries()[0].duration);
  performance.clearMarks();
});
obs.observe({ entryTypes: ['measure'] });

performance.mark('A');
doSomeLongRunningProcess(() => {
  performance.mark('B');
  performance.measure('A to B', 'A', 'B');
});

الصنف: Performance

أُضيف في الإصدار: 8.5.0.

performance.clearMarks([name‎]‎)‎

أُضيفت في الإصدار: 8.5.0

إذا لم يكن المعامل name مُزودًا، فستُمسَح كل كائنات PerformanceMark من الجدول الزمني للأداء. أما إذا كانت قيمة name مزوّدة، فستُمسح العلامة المسماة فقط.

performance.mark([name]‎)‎

أُضيفت في الإصدار: 8.5.0.

تُنشِئ مُدخل  PerformanceMark جديد في الجدول الزمني للأداء .الصنف PerformanceMark هو صنف فرعي من PerformanceEntry وفيه تكون قيمة performanceEntry.entryType دائمًا 'mark' ( مُعلّمًا). وقيمة performanceEntry.duration  دائمًا 0. تُستخدم علامات الأداء لتعليم لحظات محددة مهمة في الجدول الزمني للأداء.

(performance.measure(name, startMark, endMark

أُضيفت في الإصدار: 8.5.0.

تُنشِئ مُدخل PerformanceMeasure جديد في الجدول الزمني للأداء. الصنف  PerformanceMeasure هو صنف فرعي من الصنف PerformanceEntry فيه الخاصية performanceEntry.entryType ذات قيمة 'measure' (قياس) دائمًا، والخاصية performanceEntry.duration خاصته تقيس عدد الملي ثانية المنقضي منذ startMark و endMark.

قد يُعرِّف الوسيط startMark أي PerformanceMark موجودة في الجدول الزمني للأداء، أو قد يعرّف أي من خاصيات البصمة الزمنية (timestamp) المقدمة من قبل الصنف PerformanceNodeTiming. إذا كانت قيمة startMark المُسمّاة غير موجودة، حينذاك تُهيأ قيمة المعامل startMark وتُضبَط إلى timeOrigin افتراضيًا.

يجب أن يُعرِّف الوسيط endMark أي PerformanceMark موجودة في الجدول الزمني للأداء، أو أي من  خاصيات البصمة الزمنية (timestamp) المقدمة من خلال الصنف PerformanceNodeTiming. إذا كان العامل endMark  المسمّى غير موجود، فسوف يُرمى خطأ.

performance.nodeTiming

أُضيفت في الإصدار: 8.5.0.

  • <PerformanceNodeTiming>
  • نسخة من الصنف PerformanceNodeTiming  والتي تقدم مقاييس أداء لمراحل تشغيل Node.js محددة.

performance.now(‎)‎

أُضيفت في الإصدار: 8.5.0.

تعيد البصمة الزمنية الحالية عالية الدقة بالميلي ثانية، حيث تمثل القيمة 0 بداية عملية node الحالية.

performance.timeOrigin

أُضيفت في الإصدار: 8.5.0.

تحدد الخاصية timeOrigin بصمة زمنية عالية الدقة بالميلي ثانية والتي بدأت فيها عملية node الحالية، مقاسة بتوقيت يونكس.

performance.timerify(fn)‎

أُضيفت في الإصدار: 8.5.0.

تُغلّف الدالة بدالة جديدة والتي تقيس زمن التشغيل للدالة المُغلّفة. يجب أن تكون قيمة PerformanceObserver مشترِكة ً(subscribed) بنوع الحدث 'function' من أجل إمكانية الوصول لتفاصيل الزمن.

const {
  performance,
  PerformanceObserver
} = require('perf_hooks');

function someFunction() {
  console.log('hello world');
}

const wrapped = performance.timerify(someFunction);

const obs = new PerformanceObserver((list) => {
  console.log(list.getEntries()[0].duration);
  obs.disconnect();
});
obs.observe({ entryTypes: ['function'] });

// سوف يُنشأ مُدخل الجدول الزمني للأداء
wrapped();

الصنف PerformanceEntry

أُضيف في الإصدار: 8.5.0.

performanceEntry.duration

أُضيفت في الإصدار: 8.5.0.

العدد الكلي بالميلي ثانية المنقضي من أجل هذا المُدخل. لن تكون هذه القيمة ذات معنى من أجل جميع أنواع مدخلات الأداء.

performanceEntry.name

أُضيفت في الإصدار: 8.5.0.

اسم مُدخل الأداء.

performanceEntry.startTime

أُضيفت في الإصدار: 8.5.0.

البصمة الزمنية عالية الدقة بالميلي ثانية التي تُشير إلى زمن البداية لمُدخل الأداء.

performanceEntry.entryType

أُضيفت في الإصدار: 8.5.0.

نوع مُدخل الأداء، حاليًا قد يكون  إما 'node' أو 'mark' أو'measure' أو 'gc' أو'function' أو 'http2'.

performanceEntry.kind

أُضيفت في الإصدار: 8.5.0.

عندما تكون قيمة الخاصية performanceEntry.entryType مساويةً إلى 'gc' ، تُعرِّف الخاصية  performance.kind نوع عملية جمع القمامة (تنظيف الذاكرة) التي حصلت.

يمكن أن تكون القيمة واحدةً مما يلي:

  • perf_hooks.constants.NODE_PERFORMANCE_GC_MAJOR
  • perf_hooks.constants.NODE_PERFORMANCE_GC_MINOR
  • perf_hooks.constants.NODE_PERFORMANCE_GC_INCREMENTAL
  • perf_hooks.constants.NODE_PERFORMANCE_GC_WEAKCB

الصنف PerformanceNodeTiming extends PerformanceEntry

أُضيف في الإصدار: 8.5.0.

يقدم تفاصيل التوقيت لمنصة Node.js نفسها.

performanceNodeTiming.bootstrapComplete

أُضيفت في الإصدار: 8.5.0.

البصمة الزمنية عالية الدقة بالميلي ثانية والتي أكملت فيها عملية Node.js تمهيد التشغيل. إذا لم ينته تمهيد التشغيل بعد، فستأخد الخاصية القيمة ‎-1.

performanceNodeTiming.loopExit

أُضيفت في الإصدار: 8.5.0.

بصمة زمنية عالية الدقة بالميلي ثانية والتي انتهت عندها حلقة أحداث Node.js. إذا لم تنتهِ حلقة الأحداث بعد، فستأخذ الخاصية القيمة ‎-1. يمكن فقط أن تأخذ قيمةً لا تساوي ‎-1 في معالج الحدث 'exit'.

performanceNodeTiming.loopStart

أُضيفت في الإصدار: 8.5.0.

البصمة الزمنية عالية الدقة بالميلي ثانية والتي بدأت عندها حلقة أحداث Node.js. إذا لم تبدأ حلقة الأحداث بعد، (على سبيل المثال، في اللحظة الأولى للسكربت الرئيسي)، فستأخذ الخاصية القيمة ‎-1.

performanceNodeTiming.nodeStart

أُضيفت في الإصدار: 8.5.0.

البصمة الزمنية عالية الدقة بالميلي ثانية والذي هُيئت فيها عملية Node.js.

performanceNodeTiming.v8Start

أُضيفت في الإصدار: 8.5.0.

البصمة الزمنية عالية الدقة بالميلي ثانية والتي هُيئت فيها منصة V8.

الصنف: PerformanceObserver

new PerformanceObserver(callback)‎

أُضيف في الإصدار:8.5.0

تقدم كائنات PerformanceObserver إشعارات عندما تُضاف نسخة PerformanceEntry جديدة إلى الجدول الزمني للأداء.

const {
  performance,
  PerformanceObserver
} = require('perf_hooks');

const obs = new PerformanceObserver((list, observer) => {
  console.log(list.getEntries());
  observer.disconnect();
});
obs.observe({ entryTypes: ['mark'], buffered: true });

performance.mark('test');

بسبب أن نُسخ PerformanceObserver تقدم عبء أداء إضافي خاص بها، لا ينبغي أن تُترك النسخ مشتركةً في الإشعارات لأجل غير مُسمى. ينبغي على المستخدم قطع اتصال المراقِبات(observers) حالما لا توجد حاجة إليها.

تستدعى دالة رد النداء callback عندما تُبلَّغ PerformanceObserver عن نُسخ PerformanceEntry جديدة. تستقبل دالة رد النداء (callback) نسخة PerformanceObserverEntryList ومرجعًا إلى PerformanceObserver.

performanceObserver.disconnect(‎)‎

أُضيفت في الإصدار:8.5.0.

تفصل اتصال نسخة PerformanceObserver عن كل الإشعارات.

performanceObserver.observe(‎options)‎

أُضيفت في الإصدار: 8.5.0.

  • options <Object>
    • entryTypes <string[‎]‎>‎  مصفوفة من السلاسل النصية مُعرِّفة لأنواع نُسخ PerformanceEntry التي يهتم بها المراقب. إذا لم تكن قيمة هذا المعامل موجودةً فسوف يُرمى خطأ.
    • buffered <boolean>‎ إذا كانت true، سوف تستدعى دالة رد النداء callback للإشعارات باستخدام setImmediate(‎)‎ وستُخزَّن محليًا العديد من إشعارات  نُسخ PerformanceEntry. إذا كانت false، فسوف تكون الإشعارات آنية ومتزامنة. القيمة الافتراضية: false.

تُؤدي هذه الدالة إلى جعل نسخة الصنف PerformanceObserver مشتركةً بإشعارات النسخ الجديدة من PerformanceEntry المُعرَّفة بواسطة الخاصية options.entryTypes.

عندما تكون قيمة الخاصية options.buffered هي false، فستُستدعى دالة رد النداء callback مرةً لكل نسخة من نسخ PerformanceEntry:

const {
  performance,
  PerformanceObserver
} = require('perf_hooks');

const obs = new PerformanceObserver((list, observer) => {
 
//تُستدعى ثلاث مرات بشكل متزامن. تحوي اللائحة عنصر واحد 
});
obs.observe({ entryTypes: ['mark'] });

for (let n = 0; n < 3; n++)
  performance.mark(`test${n}`);
const {
  performance,
  PerformanceObserver
} = require('perf_hooks');

const obs = new PerformanceObserver((list, observer) => {
  
// تُستدعى مرة واحدة.  تحوي اللائحة ثلاثة عناصر 
});
obs.observe({ entryTypes: ['mark'], buffered: true });

for (let n = 0; n < 3; n++)
  performance.mark(`test${n}`);

الصنف PerformanceObserverEntryList

يُستخدم الصنف PerformanceObserverEntryList لتوفير وصول إلى نسخ PerformanceEntry المُمررة إلى PerformanceObserver.

performanceObserverEntryList.getEntries(‎)‎

أُضيفت في الإصدار:8.5.0

تعيد لائحة من كائنات PerformanceEntry مرتبة زمنيًا بالنسبة إلى performanceEntry.startTime.

performanceObserverEntryList.getEntriesByName(‎name[‎, type]‎)‎

أُضيف في الإصدار: 8.5.0.

تعيد لائحة من كائنات  PerformanceEntry  مرتبة زمنيًا حسب  performanceEntry.startTime  والتي  فيها قيمة الخاصية performanceEntry.name مساوية إلى name، واختياريًا، تكون قيمةperformanceEntry.entryType الخاصة بها مساويةً لtype.

performanceObserverEntryList.getEntriesByType(‎type)‎‎

تعيد لائحة من كائنات PerformanceEntry بترتيب زمني بالنسبة إلى performanceEntry.startTime والتي تكون فيها الخاصية performanceEntry.entryType مساويةً إلى type.

أمثلة

قياس المُدّة للعمليات غير المتزامنة

تستخدم الأمثلة التالية الخطافات غير المتزامنة  وواجهات الأداء (الواجهات البرمجية للأداء Performance APIs) لقياس المدة الفعلية لعملية منتهية المهلة (متضمنة كمية الوقت [المُتطلبة] لتنفيذ دالة رد النداء callback).

'use strict';
const async_hooks = require('async_hooks');
const {
  performance,
  PerformanceObserver
} = require('perf_hooks');

const set = new Set();
const hook = async_hooks.createHook({
  init(id, type) {
    if (type === 'Timeout') {
      performance.mark(`Timeout-${id}-Init`);
      set.add(id);
    }
  },
  destroy(id) {
    if (set.has(id)) {
      set.delete(id);
      performance.mark(`Timeout-${id}-Destroy`);
      performance.measure(`Timeout-${id}`,
                          `Timeout-${id}-Init`,
                          `Timeout-${id}-Destroy`);
    }
  }
});
hook.enable();

const obs = new PerformanceObserver((list, observer) => {
  console.log(list.getEntries()[0]);
  performance.clearMarks();
  observer.disconnect();
});
obs.observe({ entryTypes: ['measure'], buffered: true });

setTimeout(() => {}, 1000);

قياس المدّة المأخوذة لتحميل الاعتماديات

يقيس المثال التالي مدة العملية require(‎)‎ لتحميل الاعتماديات (dependencies):

'use strict';
const {
  performance,
  PerformanceObserver
} = require('perf_hooks');
const mod = require('module');

//  محاكاة تصحيح/تشغيل  الدالة المطلوبة
mod.Module.prototype.require =
  performance.timerify(mod.Module.prototype.require);
require = performance.timerify(require);

//  تفعيل المراقب
const obs = new PerformanceObserver((list) => {
  const entries = list.getEntries();
  entries.forEach((entry) => {
    console.log(`require('${entry[0]}')`, entry.duration);
  });
  obs.disconnect();
});
obs.observe({ entryTypes: ['function'], buffered: true });

require('some-module');

مصادر