Profiling

CPU Profiling

هناك نهجان رئيسيان لتوصيف وحدة المعالجة المركزية (CPU) لشفرة جوليا:

Via @profile

حيث يتم تمكين التوصيف لاستدعاء معين عبر ماكرو @profile.

julia> using Profile

julia> @profile foo()

julia> Profile.print()
Overhead ╎ [+additional indent] Count File:Line; Function
=========================================================
    ╎147  @Base/client.jl:506; _start()
        ╎ 147  @Base/client.jl:318; exec_options(opts::Base.JLOptions)
...

Triggered During Execution

يمكن أيضًا تحليل المهام التي تعمل بالفعل لفترة زمنية محددة في أي وقت يتم فيه تشغيلها بواسطة المستخدم.

لتفعيل التوصيف:

  • MacOS و FreeBSD (المنصات المعتمدة على BSD): استخدم ctrl-t أو أرسل إشارة SIGINFO إلى عملية جوليا، أي % kill -INFO $julia_pid
  • لينكس: أرسل إشارة SIGUSR1 إلى عملية جوليا أي % kill -USR1 $julia_pid
  • ويندوز: غير مدعوم حاليًا.

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

اختياريًا، قم بتعيين متغير البيئة JULIA_PROFILE_PEEK_HEAP_SNAPSHOT إلى 1 لجمع heap snapshot تلقائيًا أيضًا.

julia> foo()
##== the user sends a trigger while foo is running ==##
load: 2.53  cmd: julia 88903 running 6.16u 0.97s

======================================================================================
Information request received. A stacktrace will print followed by a 1.0 second profile
======================================================================================

signal (29): Information request: 29
__psynch_cvwait at /usr/lib/system/libsystem_kernel.dylib (unknown line)
_pthread_cond_wait at /usr/lib/system/libsystem_pthread.dylib (unknown line)
...

======================================================================
Profile collected. A report will print if the Profile module is loaded
======================================================================

Overhead ╎ [+additional indent] Count File:Line; Function
=========================================================
Thread 1 Task 0x000000011687c010 Total snapshots: 572. Utilization: 100%
   ╎147 @Base/client.jl:506; _start()
       ╎ 147 @Base/client.jl:318; exec_options(opts::Base.JLOptions)
...

Thread 2 Task 0x0000000116960010 Total snapshots: 572. Utilization: 0%
   ╎572 @Base/task.jl:587; task_done_hook(t::Task)
      ╎ 572 @Base/task.jl:879; wait()
...

Customization

يمكن ضبط مدة التوصيف عبر Profile.set_peek_duration

تقرير الملف الشخصي مقسم حسب الخيط والمهمة. مرر دالة بدون معلمات إلى Profile.peek_report[] لتجاوز ذلك. أي Profile.peek_report[] = () -> Profile.print() لإزالة أي تجميع. يمكن أيضًا تجاوز ذلك بواسطة مستهلك بيانات الملف الشخصي الخارجي.

Reference

Profile.@profileMacro
@profile

@profile <expression> يقوم بتشغيل التعبير الخاص بك مع أخذ تتبعات دورية. يتم إلحاق هذه التتبعات بذاكرة داخلية لتتبع التتبع.

source

الطرق في Profile غير مصدرة وتحتاج إلى أن تُستدعى مثل Profile.print().

Profile.clearFunction
clear()

امسح أي تتبعات موجودة من المخزن الداخلي.

source
Profile.printFunction
print([io::IO = stdout,] [data::Vector = fetch()], [lidict::Union{LineInfoDict, LineInfoFlatDict} = getdict(data)]; kwargs...)

يطبّع نتائج التقييم إلى io (بشكل افتراضي، stdout). إذا لم تقم بتزويد متجه data، سيتم استخدام المخزن الداخلي للتتبع المتراكم.

يمكن أن تكون الوسائط الرئيسية أي مجموعة من:

  • format – يحدد ما إذا كان سيتم طباعة تتبعات الأخطاء مع (افتراضي، :tree) أو بدون (:flat) تباعد يشير إلى هيكل الشجرة.
  • C – إذا كانت true، يتم عرض تتبعات الأخطاء من كود C و Fortran (عادةً ما يتم استبعادها).
  • combine – إذا كانت true (افتراضي)، يتم دمج مؤشرات التعليمات التي تتوافق مع نفس سطر الكود.
  • maxdepth – يحدد العمق الأعلى من maxdepth في تنسيق :tree.
  • sortedby – يتحكم في ترتيب تنسيق :flat. :filefuncline (افتراضي) يرتب حسب سطر المصدر، :count يرتب حسب عدد العينات المجمعة، و :overhead يرتب حسب عدد العينات التي تكبدتها كل دالة بمفردها.
  • groupby – يتحكم في التجميع عبر المهام والخيوط، أو عدم التجميع. الخيارات هي :none (افتراضي)، :thread، :task، [:thread, :task]، أو [:task, :thread] حيث يوفر الاثنان الأخيران تجميعًا متداخلًا.
  • noisefloor – يحدد الإطارات التي تتجاوز مستوى الضوضاء الاستدلالي للعينة (ينطبق فقط على تنسيق :tree). قيمة مقترحة لتجربتها هي 2.0 (القيمة الافتراضية هي 0). هذا المعامل يخفي العينات التي يكون فيها n <= noisefloor * √N، حيث n هو عدد العينات في هذا السطر، و N هو عدد العينات للوظيفة المستدعاة.
  • mincount – يحدد الطباعة لتشمل فقط تلك الأسطر التي تحتوي على ما لا يقل عن mincount حدوثات.
  • recur – يتحكم في معالجة التكرار في تنسيق :tree. :off (افتراضي) يطبع الشجرة كالمعتاد. :flat بدلاً من ذلك يضغط أي تكرار (حسب ip)، مما يظهر التأثير التقريبي لتحويل أي تكرار ذاتي إلى مكرر. :flatc يفعل نفس الشيء ولكنه يتضمن أيضًا انهيار إطارات C (قد يفعل أشياء غريبة حول jl_apply).
  • threads::Union{Int,AbstractVector{Int}} – حدد أي خيوط لتضمين لقطات منها في التقرير. لاحظ أن هذا لا يتحكم في أي خيوط تم جمع العينات عليها (والتي قد تكون قد تم جمعها أيضًا على آلة أخرى).
  • tasks::Union{Int,AbstractVector{Int}} – حدد أي مهام لتضمين لقطات منها في التقرير. لاحظ أن هذا لا يتحكم في أي مهام تم جمع العينات ضمنها.
جوليا 1.8

تم تقديم الوسائط الرئيسية groupby و threads و tasks في جوليا 1.8.

Note

التقييم على ويندوز محدود إلى الخيط الرئيسي. لم يتم أخذ عينات من الخيوط الأخرى ولن تظهر في التقرير.

source
print([io::IO = stdout,] data::Vector, lidict::LineInfoDict; kwargs...)

يطبع نتائج التقييم إلى io. يتم استخدام هذا المتغير لفحص النتائج التي تم تصديرها بواسطة استدعاء سابق لـ retrieve. قدم المتجه data من تتبعات العودة وقاموس lidict من معلومات السطر.

انظر Profile.print([io], data) للحصول على شرح للوسائط الرئيسية الصالحة.

source
Profile.initFunction
init(; n::Integer, delay::Real)

قم بتكوين delay بين تتبعات الأخطاء (مقاسة بالثواني)، وعدد n من مؤشرات التعليمات التي يمكن تخزينها لكل خيط. كل مؤشر تعليمات يتوافق مع سطر واحد من التعليمات البرمجية؛ تتكون تتبعات الأخطاء عمومًا من قائمة طويلة من مؤشرات التعليمات. لاحظ أنه يتم استخدام 6 مسافات لمؤشرات التعليمات لكل تتبع خطأ لتخزين البيانات الوصفية واثنين من علامات نهاية NULL. يمكن الحصول على الإعدادات الحالية عن طريق استدعاء هذه الوظيفة بدون أي وسائط، ويمكن تعيين كل منها بشكل مستقل باستخدام الكلمات الرئيسية أو بالترتيب (n, delay).

source
Profile.fetchFunction
fetch(;include_meta = true) -> data

إرجاع نسخة من مخزن تتبع الملفات الشخصية. لاحظ أن القيم في data لها معنى فقط على هذه الآلة في الجلسة الحالية، لأنها تعتمد على عناوين الذاكرة الدقيقة المستخدمة في التجميع JIT. هذه الوظيفة مخصصة بشكل أساسي للاستخدام الداخلي؛ قد تكون retrieve خيارًا أفضل لمعظم المستخدمين. بشكل افتراضي، يتم تضمين بيانات التعريف مثل threadid و taskid. قم بتعيين include_meta إلى false لإزالة بيانات التعريف.

source
Profile.retrieveFunction
retrieve(; kwargs...) -> data, lidict

"تصدير" نتائج التحليل في تنسيق محمول، مع إرجاع مجموعة من جميع تتبعات الأخطاء (data) وقاموس يربط مؤشرات التعليمات (المحددة للجلسة) في data بقيم LineInfo التي تخزن اسم الملف، اسم الدالة، ورقم السطر. تتيح لك هذه الدالة حفظ نتائج التحليل لتحليلها في المستقبل.

source
Profile.callersFunction
callers(funcname, [data, lidict], [filename=<filename>], [linerange=<start:stop>]) -> Vector{Tuple{count, lineinfo}}

بناءً على تشغيل سابقة للتقييم، حدد من استدعى دالة معينة. يسمح لك تقديم اسم الملف (وخيارياً، نطاق أرقام الأسطر التي تم تعريف الدالة عليها) بتفريق طريقة مفرطة التحميل. القيمة المعادة هي متجه يحتوي على عدد المكالمات ومعلومات السطر حول المستدعي. يمكن للمرء اختيارياً تقديم بيانات تتبع data تم الحصول عليها من retrieve؛ خلاف ذلك، يتم استخدام مخزن التقييم الداخلي الحالي.

source
Profile.clear_malloc_dataFunction
clear_malloc_data()

يمسح أي بيانات تخص تخصيص الذاكرة المخزنة عند تشغيل جوليا مع --track-allocation. نفذ الأمر (الأوامر) التي تريد اختبارها (لإجبار JIT-compilation)، ثم استدع clear_malloc_data. ثم نفذ الأمر (الأوامر) مرة أخرى، اخرج من جوليا، وافحص ملفات *.mem الناتجة.

source
Profile.get_peek_durationFunction
get_peek_duration()

احصل على المدة بالثواني لملف التعريف "peek" الذي يتم تفعيله عبر SIGINFO أو SIGUSR1، اعتمادًا على النظام الأساسي.

source
Profile.set_peek_durationFunction
set_peek_duration(t::Float64)

قم بتعيين المدة بالثواني لملف التعريف "peek" الذي يتم تفعيله عبر SIGINFO أو SIGUSR1، اعتمادًا على النظام الأساسي.

source

Memory profiling

Profile.Allocs.@profileMacro
Profile.Allocs.@profile [sample_rate=0.1] expr

قم بتسجيل تخصيصات الذاكرة التي تحدث أثناء expr، مع إرجاع كل من النتيجة وهيكل AllocResults.

معدل العينة 1.0 سيسجل كل شيء؛ 0.0 لن يسجل أي شيء.

julia> Profile.Allocs.@profile sample_rate=0.01 peakflops()
1.03733270279065e11

julia> results = Profile.Allocs.fetch()

julia> last(sort(results.allocs, by=x->x.size))
Profile.Allocs.Alloc(Vector{Any}, Base.StackTraces.StackFrame[_new_array_ at array.c:127, ...], 5576)

راجع برنامج التعليمات الخاص بالتسجيل في وثائق جوليا لمزيد من المعلومات.

Julia 1.11

لم تتمكن الإصدارات القديمة من جوليا من التقاط الأنواع في جميع الحالات. في الإصدارات القديمة من جوليا، إذا رأيت تخصيصًا من نوع Profile.Allocs.UnknownType، فهذا يعني أن أداة التسجيل لا تعرف نوع الكائن الذي تم تخصيصه. حدث هذا بشكل رئيسي عندما كان التخصيص يأتي من كود تم إنشاؤه بواسطة المترجم. راجع issue #43688 لمزيد من المعلومات.

منذ جوليا 1.11، يجب أن تحتوي جميع التخصيصات على نوع مُبلغ عنه.

Julia 1.8

تمت إضافة أداة تسجيل التخصيصات في جوليا 1.8.

source

الطرق في Profile.Allocs غير مصدرة وتحتاج إلى أن تُستدعى مثل Profile.Allocs.fetch().

Profile.Allocs.clearFunction
Profile.Allocs.clear()

امسح جميع معلومات التخصيص التي تم تحليلها مسبقًا من الذاكرة.

source
Profile.Allocs.printFunction
Profile.Allocs.print([io::IO = stdout,] [data::AllocResults = fetch()]; kwargs...)

يطبّع نتائج التقييم إلى io (بشكل افتراضي، stdout). إذا لم تقم بتزويد متجه data، سيتم استخدام المخزن الداخلي للتتبع المتراكم.

انظر Profile.print للحصول على شرح للوسائط الرئيسية الصالحة.

source
Profile.Allocs.fetchFunction
Profile.Allocs.fetch()

استرجع التخصيصات المسجلة، وقم بفك تشفيرها إلى كائنات جوليا التي يمكن تحليلها.

source
Profile.Allocs.startFunction
Profile.Allocs.start(sample_rate::Real)

ابدأ بتسجيل التخصيصات بمعدل العينة المعطى. سيقوم معدل العينة 1.0 بتسجيل كل شيء؛ بينما سيقوم 0.0 بتسجيل لا شيء.

source

Heap Snapshots

Profile.take_heap_snapshotFunction
Profile.take_heap_snapshot(filepath::String, all_one::Bool=false, streaming=false)
Profile.take_heap_snapshot(all_one::Bool=false; dir::String, streaming=false)

اكتب لقطة من الذاكرة، بتنسيق JSON المتوقع من عارض لقطة ذاكرة أدوات مطور Chrome (.heapsnapshot extension) إلى ملف ($pid_$timestamp.heapsnapshot) في الدليل الحالي بشكل افتراضي (أو tempdir إذا كان الدليل الحالي غير قابل للكتابة)، أو في dir إذا تم تقديمه، أو المسار الكامل للملف المعطى، أو تدفق IO.

إذا كان all_one صحيحًا، فقم بالإبلاغ عن حجم كل كائن كواحد حتى يمكن عدها بسهولة. خلاف ذلك، قم بالإبلاغ عن الحجم الفعلي.

إذا كان streaming صحيحًا، فسوف نقوم ببث بيانات اللقطة إلى أربعة ملفات، باستخدام filepath كبادئة، لتجنب الحاجة إلى الاحتفاظ باللقطة الكاملة في الذاكرة. يجب استخدام هذا الخيار في أي إعداد حيث تكون الذاكرة لديك محدودة. يمكن بعد ذلك إعادة تجميع هذه الملفات عن طريق استدعاء Profile.HeapSnapshot.assemble_snapshot()، والذي يمكن القيام به في وضع عدم الاتصال.

ملاحظة: نوصي بشدة بتعيين streaming=true لأسباب تتعلق بالأداء. يتطلب إعادة بناء اللقطة من الأجزاء الاحتفاظ باللقطة الكاملة في الذاكرة، لذا إذا كانت اللقطة كبيرة، يمكنك نفاد الذاكرة أثناء معالجتها. يسمح البث لك بإعادة بناء اللقطة في وضع عدم الاتصال، بعد انتهاء عبء العمل الخاص بك. إذا حاولت جمع لقطة مع streaming=false (الإعداد الافتراضي، للتوافق مع الإصدارات السابقة) وتم قتل عمليتك، لاحظ أن هذا سيحفظ دائمًا الأجزاء في نفس الدليل مثل filepath المقدم، لذا يمكنك إعادة بناء اللقطة بعد ذلك، عبر assemble_snapshot().

source

الطرق في Profile غير مصدرة وتحتاج إلى أن تُستدعى مثل Profile.take_heap_snapshot().

julia> using Profile

julia> Profile.take_heap_snapshot("snapshot.heapsnapshot")

يتتبع ويسجل كائنات جوليا في الذاكرة. هذا يسجل فقط الكائنات المعروفة لجمع القمامة في جوليا. الذاكرة المخصصة من قبل المكتبات الخارجية التي لا يديرها جامع القمامة لن تظهر في اللقطة.

لتجنب نفاد الذاكرة أثناء تسجيل لقطة الذاكرة، أضفنا خيار البث لبث لقطة الذاكرة إلى أربعة ملفات،

julia> using Profile

julia> Profile.take_heap_snapshot("snapshot"; streaming=true)

حيث "snapshot" هو مسار الملف كبادئة للملفات المولدة.

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

julia> using Profile

julia> Profile.HeapSnapshot.assemble_snapshot("snapshot", "snapshot.heapsnapshot")

يمكن تحميل ملف لقطة الكومة الناتجة إلى أدوات مطوري Chrome لعرضه. لمزيد من المعلومات، راجع chrome devtools docs. بديل لتحليل لقطات كومة Chromium هو استخدام ملحق VS Code ms-vscode.vscode-js-profile-flame.

لقطات كومة Firefox هي بتنسيق مختلف، وFirefox حالياً قد لا يُستخدم لعرض لقطات الكومة التي تم إنشاؤها بواسطة Julia.