Skip to content
ClickHouse Docs
ClickHouse DocsClickHouse Docs

تنميط ClickHouse باستخدام XRay من LLVM

أنواع أدوات التنميط

يتضمن LLVM بالفعل أداة تُدرج تعليمات تتبّع داخل الشيفرة، ما يتيح لنا إجراء التنميط عبر تضمين الشيفرة . وعلى خلاف التنميط بالعينات أو التنميط الإحصائي، فهو بالغ الدقة من دون فقدان أي استدعاءات، لكنه يتطلب تضمين الشيفرة ويستهلك موارد أكثر.

وباختصار، يضيف مُنَمِّط تضمين الشيفرة تعليمات جديدة لتتبّع استدعاءات جميع الدوال. أما أدوات التنميط الإحصائي فتتيح لنا تشغيل الشيفرة من دون الحاجة إلى أي تغييرات، مع أخذ لقطات دوريًا لمعاينة حالة التطبيق. لذلك، لا تُؤخذ في الاعتبار إلا الدوال التي تكون قيد التنفيذ عند التقاط اللقطة. ويُعد perf من أشهر أدوات التنميط الإحصائي.

تنميط ClickHouse باستخدام تكامل XRay

في ClickHouse 25.12، دُمج XRay لإضافة نقاط تتبّع جديدة إلى الدوال بسلاسة. لذلك، فإن أي إصدار رسمي يأتي مزودًا أصلًا بهذه الميزة التي يمكن تشغيلها عند الطلب، من دون التأثير في الأداء العام عندما لا تكون مفعّلة. والفكرة هي تفعيل الحد الأدنى من نقاط التتبّع للحصول على معلومات قيّمة.

يمكننا إضافة نقطة قياس جديدة لتحليل الأداء باستخدام عبارة SYSTEM INSTRUMENT ADD PROFILE. ويمكن جمع الدوال المطلوب قياسها من جدول النظام system.symbols. لنفترض أننا نريد تحليل أداء الدالة sleepForNanoseconds، وهي دالة مناسبة للتحقق من المدة التي يستغرقها تنفيذها.

SYSTEM INSTRUMENT ADD 'sleepForNanoseconds' PROFILE

ثم نتركه يعمل طوال الفترة الزمنية التي نريد تحليلها، ثم نوقفه.

SYSTEM INSTRUMENT REMOVE ALL

نحوّل البيانات المُجمَّعة في system.trace_log إلى تنسيق Chrome لتصوّرها في Perfetto. لاحظ query_id و cpu_id و stacktrace في كل إدخال.

الترتيب الزمني

تنميط تطبيق أصلي باستخدام XRay

يُترك القسم التالي كمرجع لفهم كيفية عمل XRay خلف الكواليس، وكيف يمكن استخدامه مباشرةً ومن دون إعدادات إضافية لتحليل أداء تطبيق أصلي.

أضف التتبّع إلى الشيفرة

لنفترض وجود الشيفرة المصدرية التالية:

#include <chrono>
#include <cstdio>
#include <thread>

void one()
{
    std::this_thread::sleep_for(std::chrono::milliseconds(10));
}

void two()
{
    std::this_thread::sleep_for(std::chrono::milliseconds(5));
}

int main()
{
    printf("Start\n");

    for (int i = 0; i < 10; ++i)
    {
        one();
        two();
    }

    printf("Finish\n");
}

لكي نُمكّن الرصد باستخدام XRay، نحتاج إلى إضافة بعض الخيارات كما يلي:

clang++ -o test test.cpp -fxray-instrument -fxray-instruction-threshold=1
  • يلزم استخدام -fxray-instrument لإضافة التتبّع إلى الشيفرة.
  • يُستخدم -fxray-instruction-threshold=1 لكي يضيف التتبّع إلى جميع الدوال، حتى إن كانت صغيرة جدًا كما في مثالنا. بشكل افتراضي، يُضاف التتبّع إلى الدوال التي تحتوي على 200 تعليمة على الأقل.

يمكننا التأكد من أن الشيفرة جرى تجهيزها بالتتبّع على نحو صحيح من خلال التحقق من وجود قسم جديد في الملف التنفيذي:

objdump -h -j xray_instr_map test

test:     file format elf64-x86-64

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
 17 xray_instr_map 000005c0  000000000002f91c  000000000002f91c  0002f91c  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA

شغّل العملية باستخدام قيم متغيّرات البيئة المناسبة لجمع التتبّع

بشكلٍ افتراضي، لا تُجمع بيانات مُنَمِّط إلا إذا طُلب ذلك صراحةً. وبعبارة أخرى، ما لم نكن نجري profiling، فإن الكلفة الإضافية تكون شبه معدومة. يمكننا تعيين قيم مختلفة لـ XRAY_OPTIONS من أجل تحديد وقت بدء مُنَمِّط في جمع البيانات وكيفية تنفيذ ذلك.

XRAY_OPTIONS="patch_premain=true xray_mode=xray-basic verbosity=1" ./test
==74394==XRay: Log file in 'xray-log.test.14imlN'
Start
Finish
==74394==Cleaned up log for TID: 74394

تحويل التتبّع

يمكن تحويل عمليات التتبّع في XRay إلى عدة تنسيقات. ويُعد تنسيق trace_event مفيدًا جدًا لأنه سهل التحليل، وتدعمه بالفعل مجموعة من الأدوات، لذا سنستخدمه:

llvm-xray convert --symbolize --instr_map=./test --output-format=trace_event xray-log.test.14imlN | gzip > test-trace.txt.gz

تصوّر التتبّع

يمكننا استخدام واجهات مستخدم مستندة إلى الويب مثل speedscope.app أو Perfetto.

في حين أن Perfetto يسهّل تصوّر عدة سلاسل تنفيذ والاستعلام عن البيانات، فإن speedscope أفضل لإنشاء flamegraph وعرض sandwich لبياناتك.

الترتيب حسب الزمن

الترتيب حسب الزمن

مرجّح إلى اليسار

مرجّح-إلى-اليسار

ساندويتش

ساندويتش

اطّلع على الوثائق

Navigation