'\" t .\" Man page generated from reStructuredText .\" by the Docutils 0.23 manpage writer. . . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .TH "POLLY" "1" "Jun 21, 2026" "22" "Polly" .SH "نام (NAME)" polly \- بهینه‌ساز حلقه مبتنی بر مدل چندوجهی برای LLVM .SH "یادداشت‌های انتشار (RELEASE NOTES)" .sp در Polly 22 تغییرات مهم زیر اعمال شده است. .SH "معماری (THE ARCHITECTURE)" .sp ابزار Polly یک بهینه‌ساز حلقه برای LLVM است. این ابزار کار خود را از LLVM\-IR آغاز کرده و هسته‌های حلقهٔ مهم و قابل توجه را شناسایی و استخراج می‌کند. برای هر هسته، یک مدل ریاضی به دست می‌آید که محاسبات مجزا و دسترسی‌های حافظه در هسته‌ها را به‌طور دقیق توصیف می‌کند. در Polly انواع تحلیل‌ها و تبدیل‌های کد روی این مدل ریاضی انجام می‌شود. پس از اشتقاق و اعمال تمامی بهینه‌سازی‌ها، LLVM\-IR بهینه‌شده بازتولید شده و در ماژول LLVM\-IR درج می‌گردد. [تصویر] .SS "Polly در خط لوله گذر LLVM (Polly in the LLVM pass pipeline)" .sp خط لولهٔ استاندارد گذر LLVM آن‌گونه که در حالت‌های \-O1/\-O2/\-O3 در clang/opt استفاده می‌شود، از دنباله‌ای از گذرها تشکیل شده است که می‌توان آن‌ها را در فازهای مفهومی متفاوتی دسته‌بندی کرد. فاز نخست، که در اینجا آن را \fBCanonicalization\fP (متعارف‌سازی) می‌نامیم، یک فاز متعارف‌سازی اسکالر است که شامل گذرهایی نظیر \-mem2reg، \-instcombine، \-cfgsimplify یا باز کردن زودهنگام حلقه‌ها (early loop unrolling) می‌باشد. هدف آن حذف و ساده‌سازی IR داده‌شده تا جای ممکن، با تمرکز عمده بر بهینه‌سازی‌های اسکالر است. فاز دوم از سه گروه مفهومی تشکیل شده است که در به‌اصطلاح \fBInliner cycle\fP (چرخه درون‌ریزی) اجرا می‌شوند؛ این فاز مجدداً شامل مجموعه‌ای از گذرهای \fBScalar Simplification\fP (ساده‌سازی اسکالر)، مجموعه‌ای از \fBSimple Loop Optimizations\fP (بهینه‌سازی‌های ساده حلقه) و خود \fBInliner\fP (درون‌ریز) است. گرچه این گذرها بخش عمده‌ای از خط لوله گذر LLVM را تشکیل می‌دهند، اما هدف اصلی آن‌ها همچنان متعارف‌سازی بدون از دست دادن اطلاعات معنایی است که تحلیل‌های بعدی را پیچیده می‌کند. به‌عنوان بخشی از چرخه درون‌ریزی، درون‌ریز LLVM به‌صورت گام‌به‌گام تلاش می‌کند توابع را درون‌ریزی (inline) کند، گذرهای متعارف‌سازی را برای بهره‌برداری از فرصت‌های ساده‌سازیِ تازه آشکارشده اجرا کند، و سپس سعی می‌کند توابع ساده‌ترشده را مجدداً درون‌ریزی نماید. برخی از بهینه‌سازی‌های ساده حلقه به عنوان بخشی از چرخه درون‌ریزی اجرا می‌شوند. با وجود اینکه آن‌ها بهینه‌سازی‌هایی را اعمال می‌کنند، هدف اصلی‌شان همچنان ساده‌سازی کد برنامه است. جابه‌جایی کد ناوردای حلقه (Loop invariant code motion) یکی از همین بهینه‌سازی‌هاست که علاوه بر سودمند بودن برای کارایی برنامه، به ما امکان می‌دهد محاسبات را به خارج از حلقه‌ها منتقل کنیم و در بهترین حالت امکان حذف کامل برخی حلقه‌ها را فراهم می‌سازد. تنها پس از پایان چرخه درون‌ریزی است که آخرین فاز یعنی \fBTarget Specialization\fP (اختصاصی‌سازی هدف) اجرا می‌شود؛ جایی که پیچیدگی IR به‌طور عمدی افزایش می‌یابد تا از ویژگی‌های خاص معماری هدف برای بیشینه‌سازی کارایی اجرا روی دستگاه مقصد بهره گرفته شود. یکی از بهینه‌سازی‌های اصلی در این فاز، برداری‌سازی (vectorization) است، اما باز کردن حلقه مختص به هدف (target specific loop unrolling) یا برخی تبدیل‌های حلقه (مانند توزیع یا distribution) را نیز در بر می‌گیرد که فرصت‌های بیشتری برای برداری‌سازی فراهم می‌کنند. [تصویر] .sp ابزار Polly از نظر مفهومی می‌تواند در سه موقعیت مختلف در خط لوله گذر اجرا شود: به‌عنوان یک بهینه‌ساز زودهنگام قبل از خط لوله استاندارد گذر LLVM، به‌عنوان یک بهینه‌ساز دیرهنگام در قالب دنباله اختصاصی‌سازی هدف، و از نظر تئوری همچنین همراه با بهینه‌سازی‌های حلقه در چرخه درون‌ریزی. ما تنها دو گزینه نخست را بررسی می‌کنیم، چرا که اجرای Polly در حلقه درون‌ریزی احتمالاً کار درون‌ریز را مختل می‌کند و بنابراین ایده مناسبی نیست. [تصویر] .sp اجرای زودهنگام Polly پیش از خط لوله استاندارد گذر این مزیت را دارد که LLVM\-IR پردازش‌شده توسط Polly هنوز بسیار به کد ورودی اصلی نزدیک است. بنابراین، احتمال کمتری وجود دارد که تبدیل‌های اعمال‌شده توسط LLVM، کد IR را به شیوه‌هایی تغییر دهند که درک آن برای برنامه‌نویس دشوار باشد. در نتیجه، بازخورد به کاربر احتمالاً بهتر است و احتمال کمتری وجود دارد هسته‌هایی که در زبان C کاملاً مناسب Polly به نظر می‌رسند، طوری دگرگون شده باشند که Polly دیگر قادر به مدیریت آن‌ها نباشد. از سوی دیگر، کدهایی که برای بهینه‌سازی نیازمند درون‌ریزی هستند، در صورتی که Polly در این موقعیت زمان‌بندی شود سودی نخواهند برد. مجموعه اضافی گذرهای متعارف‌سازیِ مورد نیاز منجر به افزایشی اندک اما عمومی در زمان کامپایل، و برخی تغییرات تصادفی در کارایی زمان اجرا به دلیل ارسال IR اندکی متفاوت به بهینه‌سازها خواهد شد. برای وادار کردن Polly به اجرای زودهنگام در خط لوله گذر، از گزینهٔ \fI\-polly\-position=early\fP استفاده کنید (پیش‌فرض فعلی). [تصویر] .sp اجرای Polly درست پیش از برداری‌ساز (vectorizer) این مزیت را دارد که چرخه کامل درون‌ریزی اجرا شده است و در نتیجه حتی کدهای به‌شدت مبتنی بر الگو (template) در ++C نیز از نظر تئوری می‌توانند از Polly بهره‌مند شوند (البته کارهای بیشتری لازم است تا Polly در اینجا واقعاً مؤثر واقع شود). از آنجا که IR ارائه‌شده به Polly قبلاً متعارف‌سازی شده است، نیازی به اجرای گذرهای متعارف‌سازی اضافی نیز وجود ندارد. زمان کلی کامپایل تقریباً تحت تأثیر Polly قرار نمی‌گیرد، زیرا شناسایی هسته‌های حلقه عموماً بسیار سریع است و گذرهای بهینه‌سازی و پاک‌سازیِ واقعی فقط روی توابعی اجرا می‌شوند که دارای هسته‌های حلقه باارزش برای بهینه‌سازی باشند. با این حال، به دلیل بهینه‌سازی‌های متعددی که LLVM پیش از Polly اجرا می‌کند، کدهای IR که به Polly می‌رسند اغلب دارای وابستگی‌های اسکالر اضافی هستند که بازدهی Polly را بسیار کاهش می‌دهند. برای وادار کردن Polly به اجرا قبل از برداری‌ساز در خط لوله گذر، از گزینهٔ \fI\-polly\-position=before\-vectorizer\fP\& استفاده کنید. این موقعیت هنوز پیش‌فرض Polly نیست، اما تلاش‌ها برای مؤثر ساختن آن حتی در حضور وابستگی‌های اسکالر در جریان است. پس از تکمیل این کار، Polly به احتمال زیاد به‌طور پیش‌فرض از این موقعیت استفاده خواهد کرد. [تصویر].SH "استفاده از POLLY همراه با CLANG (USING POLLY WITH CLANG)" .sp این مستندات به نحوه استفاده از Polly در Clang برای بهینه‌سازی خودکار کدهای C/C++ در طول فرایند کامپایل می‌پردازد. .sp \fBهشدار:\fP .INDENT 0.0 .INDENT 3.5 هشدار: ابزارهای clang/LLVM/Polly باید با یکدیگر همگام باشند (از یک revision یکسان کامپایل شده باشند). .UNINDENT .UNINDENT .SS در دسترس قرار دادن Polly در Clang .sp چنانچه Polly پیش از کامپایل در tools/polly دریافت (checked out) شده باشد، از طریق clang، opt و bugpoint در دسترس خواهد بود. به هیچ پیکربندی بیشتری نیاز نیست. .SS بهینه‌سازی با Polly .sp بهینه‌سازی با Polly به‌سادگی افزودن \-O3 \-mllvm \-polly به فلگ‌های کامپایلر شما است (Polly در دسترس نخواهد بود مگر اینکه بهینه‌سازی‌ها فعال باشند، مانند \-O1، \-O2، \-O3؛ بهینه‌سازی برای حجم با \-Os یا \-Oz توصیه نمی‌شود). .INDENT 0.0 .INDENT 3.5 .sp .EX clang \-O3 \-mllvm \-polly file.c .EE .UNINDENT .UNINDENT .SS تولید خودکار کد OpenMP .sp برای شناسایی خودکار حلقه‌های موازی و تولید کد OpenMP برای آن‌ها، باید \-mllvm \-polly\-parallel \-lgomp را نیز به CFLAGS خود اضافه کنید. .INDENT 0.0 .INDENT 3.5 .sp .EX clang \-O3 \-mllvm \-polly \-mllvm \-polly\-parallel \-lgomp file.c .EE .UNINDENT .UNINDENT .SS تعویض backend مربوط به OpenMP .sp سوئیچ خط فرمان زیر امکان انتخاب OpenMP\-backend مربوط به Polly را فراهم می‌کند: .INDENT 0.0 .INDENT 3.5 .INDENT 0.0 .TP .B \-polly\-omp\-backend[=BACKEND] انتخاب backend مربوط به OpenMP؛ مقدار BACKEND می‌تواند \(aqGNU\(aq (پیش‌فرض) یا \(aqLLVM\(aq باشد؛ .UNINDENT .UNINDENT .UNINDENT .sp رفتار backendهای OpenMP را می‌توان با استفاده از سوئیچ‌های خط فرمان زیر دقیق‌تر تنظیم کرد: .INDENT 0.0 .INDENT 3.5 .INDENT 0.0 .TP .B \-polly\-num\-threads[=NUM] تنظیم تعداد نخ‌ها (threads) برای استفاده؛ NUM می‌تواند هر عدد صحیح مثبتی باشد (پیش‌فرض: 0، که معادل خودکار/OMP runtime است)؛ .TP .B \-polly\-scheduling[=SCHED] تنظیم نوع زمان‌بندی OpenMP؛ مقدار SCHED می‌تواند \(aqstatic\(aq، \(aqdynamic\(aq، \(aqguided\(aq یا \(aqruntime\(aq (پیش‌فرض) باشد؛ .TP .B \-polly\-scheduling\-chunksize[=CHUNK] تنظیم اندازه تکه (chunksize برای نوع زمان‌بندی انتخاب‌شده)؛ CHUNK می‌تواند هر عدد صحیح کاملاً مثبتی باشد (در غیر این صورت، پیش‌فرض 1 خواهد بود)؛ .UNINDENT .UNINDENT .UNINDENT .sp توجه داشته باشید که در زمان نگارش این متن، backend مربوط به GNU تنها می‌تواند از سوئیچ‌های \fIpolly\-num\-threads\fP و \fIpolly\-scheduling\fP استفاده کند که در مورد دومی نیز مقدار حتماً باید برابر با \(dqruntime\(dq تنظیم شود. .sp مثال: استفاده از backend جایگزین با زمان‌بندی پویا (dynamic)، چهار نخ و chunksize برابر با یک (سوئیچ‌های اضافی). .INDENT 0.0 .INDENT 3.5 .sp .EX \-mllvm \-polly\-omp\-backend=LLVM \-mllvm \-polly\-num\-threads=4 \-mllvm \-polly\-scheduling=dynamic \-mllvm \-polly\-scheduling\-chunksize=1 .EE .UNINDENT .UNINDENT.SS تولید خودکار کد برداری .sp تولید خودکار کد برداری را می‌توان با افزودن \-mllvm \-polly\-vectorizer=stripmine به CFLAGS خود فعال کرد. .INDENT 0.0 .INDENT 3.5 .sp .EX clang \-O3 \-mllvm \-polly \-mllvm \-polly\-vectorizer=stripmine file.c .EE .UNINDENT .UNINDENT .SS جداسازی گذرهای Polly .sp گذرهای تحلیل و تبدیل Polly همراه با بسیاری از گذرهای دیگر در خط لولهٔ مدیر گذر (pass manager) اجرا می‌شوند. برخی از گذرهایی که پیش از Polly اجرا می‌شوند، برای کارکرد آن ضروری هستند؛ برای نمونه کانونیکال‌سازی حلقه‌ها. بنابراین Polly قادر نیست کد را مستقیماً از خروجی \-O0 در clang بهینه‌سازی کند. .sp برای به‌دست آوردن LLVM\-IR که Polly در خط لولهٔ بهینه‌سازی می‌بیند، از این دستور استفاده کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX clang file.c \-c \-O3 \-mllvm \-polly \-mllvm \-polly\-dump\-before\-file=before\-polly.ll .EE .UNINDENT .UNINDENT .sp این دستور فایلی با نام \(aqbefore\-polly.ll\(aq حاوی LLVM\-IR ارسال‌شده به polly، پس از تبدیل SSA، کانونیکال‌سازی حلقه‌ها، درون‌خط‌سازی (inlining) و دیگر گذرها را می‌نویسد. .sp پس از آن، هر گذر Polly را می‌توان با استفاده از ابزار \(aqopt\(aq روی \(aqbefore\-polly.ll\(aq اجرا کرد. برای پی بردن به اینکه کدام گذرهای Polly در خط لولهٔ استاندارد فعال هستند، خروجی زیر را بررسی کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX clang file.c \-c \-O3 \-mllvm \-polly \-mllvm \-debug\-pass=Arguments .EE .UNINDENT .UNINDENT .sp گذرهای Polly مواردی هستند که بین \(aq\-polly\-detect\(aq و \(aq\-polly\-codegen\(aq قرار دارند. گذرهای تحلیلی را می‌توان نادیده گرفت. در زمان نگارش این مستند، خط لولهٔ پیش‌فرض گذرهای Polly به شرح زیر است: .INDENT 0.0 .INDENT 3.5 .sp .EX opt before\-polly.ll \-polly\-simplify \-polly\-optree \-polly\-delicm \-polly\-simplify \-polly\-prune\-unprofitable \-polly\-opt\-isl \-polly\-codegen .EE .UNINDENT .UNINDENT .sp توجه داشته باشید که این روش از مدیر گذر قدیمی/میراثی (legacy) در LLVM استفاده می‌کند. .sp برای کامل بودن مطلب، در اینجا چند روش دیگر برای تولید IR مناسب پردازش با Polly از کدهای منبع C/C++/Objective C آورده شده است. روش پیشین، روش توصیه‌شده است. .sp دستور زیر LLVM\-IR بهینه‌نشده (\(aq\-O0\(aq که پیش‌فرض است) را تولید کرده و گذرهای کانونیکال‌سازی را روی آن اجرا می‌کند (\(aq\-polly\-canonicalize\(aq). این روش شامل تمام گذرهایی که در خط لولهٔ پیش‌فرض پیش از Polly اجرا می‌شوند /نمی‌شود/. گزینهٔ \(aq\-disable\-O0\-optnone\(aq الزامی است زیرا در غیر این صورت clang یک صفت \(aqoptnone\(aq را به تمام توابع اضافه می‌کند تا توسط اکثر گذرهای بهینه‌سازی نادیده گرفته شوند. هدف از این کار، جلوگیری از بهینه‌سازی این توابع در فاز پیوند توسط بیلد‌های LTO است. .INDENT 0.0 .INDENT 3.5 .sp .EX clang file.c \-c \-O0 \-Xclang \-disable\-O0\-optnone \-emit\-llvm \-S \-o \- | opt \-polly\-canonicalize \-S .EE .UNINDENT .UNINDENT .sp گزینهٔ \(aq\-disable\-llvm\-passes\(aq تمام گذرهای LLVM، حتی مواردی که در \-O0 اجرا می‌شوند را غیرفعال می‌کند. ارسال \-O1 (یا هر سطح بهینه‌سازی دیگری غیر از \-O0) از افزوده شدن صفت \(aqoptnone\(aq جلوگیری می‌کند. .INDENT 0.0 .INDENT 3.5 .sp .EX clang file.c \-c \-O1 \-Xclang \-disable\-llvm\-passes \-emit\-llvm \-S \-o \- | opt \-polly\-canonicalize \-S .EE .UNINDENT .UNINDENT .sp به عنوان یک راهکار دیگر، می‌توان Polly را به ابتدای خط لولهٔ گذرها منتقل کرد و سپس خروجی آن را استخراج (dump) نمود. این کار به صورت ضمنی گذرهای \(aq\-polly\-canonicalize\(aq را اجرا می‌کند. .INDENT 0.0 .INDENT 3.5 .sp .EX clang file.c \-c \-O3 \-mllvm \-polly \-mllvm \-polly\-position=early \-mllvm \-polly\-dump\-before\-file=before\-polly.ll .EE .UNINDENT .UNINDENT.SS گزینه‌های بیشتر .sp ابزار Polly از گزینه‌های بیشتری پشتیبانی می‌کند که عمدتاً برای توسعه یا تحلیل Polly مفید هستند. گزینه‌های مربوطه را می‌توان با افزودن \-mllvm \-option\-name به CFLAGS یا خط فرمان clang اضافه کرد. .SS محدود کردن Polly به یک تابع واحد .sp برای محدود کردن اجرای Polly به یک تابع خاص، از گزینهٔ \-polly\-only\-func=functionname استفاده کنید. .SS غیرفعال‌سازی تولید LLVM\-IR .sp ابزار Polly به‌طور معمول LLVM\-IR را از نمایش چندوجهی بازتولید می‌کند. برای دیدن تنها اثرات تبدیل آماده‌سازی و غیرفعال‌سازی تولید کد Polly، گزینهٔ polly\-no\-codegen را اضافه کنید. .SS نمای گرافیکی SCoPها .sp ابزار Polly می‌تواند از graphviz برای نمایش SCoPهایی که در یک برنامه شناسایی می‌کند استفاده کند. گزینه‌های مربوطه عبارتند از \-polly\-show، \-polly\-show\-only، \-polly\-dot و \-polly\-dot\-only. گزینه‌های \(aqshow\(aq به‌طور خودکار dotty یا یک نمایش‌دهندهٔ دیگر graphviz را برای نمایش گرافیکی SCoPها اجرا می‌کنند. گزینه‌های \(aqdot\(aq برای هر تابع یک فایل dot ذخیره می‌کنند که SCoPهای شناسایی‌شده را برجسته می‌سازد. اگر \(aqonly\(aq به انتهای گزینه افزوده شود، بلوک‌های پایه بدون دستورهایی که در بر دارند نشان داده می‌شوند. .SS تغییر یا غیرفعال کردن بهینه‌ساز .sp ابزار Polly به‌طور پیش‌فرض از بهینه‌ساز زمان‌بندی isl استفاده می‌کند. بهینه‌ساز isl با استفاده از الگوریتم Pluto برای محلی‌سازی داده‌ها (data-locality) و موازی‌سازی بهینه‌سازی انجام می‌دهد. برای غیرفعال کردن کامل بهینه‌ساز از گزینهٔ \-polly\-optimizer=none استفاده کنید. .SS غیرفعال‌سازی کاشی‌کاری (tiling) در بهینه‌ساز .sp به‌طور پیش‌فرض هر دو بهینه‌ساز در صورت امکان کاشی‌کاری را انجام می‌دهند. در صورتی که این مورد مطلوب نباشد، می‌توان از گزینهٔ \-polly\-tiling=false برای غیرفعال کردن آن استفاده کرد. (این گزینه کاشی‌کاری را برای هر دو بهینه‌ساز غیرفعال می‌کند). .SS درون‌ریزی / برون‌ریزی (Import / Export) .sp پرچم‌های \-polly\-import و \-polly\-export امکان برون‌ریزی و درون‌ریزی مجدد نمایش چندوجهی را فراهم می‌کنند. با برون‌ریزی، ویرایش و درون‌ریزی مجدد نمایش چندوجهی، تبدیل‌هایی که به‌صورت خارجی محاسبه شده‌اند قابل اعمال خواهند بود. این امر بهینه‌سازهای خارجی یا بهینه‌سازی دستی SCoPهای خاص را ممکن می‌سازد. .SS مشاهده عیب‌یابی‌های Polly با opt\-viewer .sp پرچم \-fsave\-optimization\-record هنگام کامپایل برنامه، فایل‌های .opt.yaml را تولید خواهد کرد. این فایل‌های yaml حاوی اطلاعاتی دربارهٔ هر اعلان (remark) ارائه‌شده هستند. اطمینان حاصل کنید که Python 2.7 را به همراه بسته‌های پایتون PyYaml و Pygments در اختیار دارید. برای اجرای opt\-viewer: .INDENT 0.0 .INDENT 3.5 .sp .EX llvm/tools/opt\-viewer/opt\-viewer.py \-source\-dir /path/to/program/src/ \e /path/to/program/src/foo.opt.yaml \e /path/to/program/src/bar.opt.yaml \e \-o ./output .EE .UNINDENT .UNINDENT .sp تمام فایل‌های yaml را بگنجانید (هنگام تعیین این‌که کدام فایل‌های yaml مشاهده شوند، از *.opt.yaml استفاده کنید) تا تمام عیب‌یابی‌های برنامه در opt\-viewer قابل مشاهده باشند. برنامه را با PGO کامپایل کنید \% تا اطلاعات بسامد اجرا (Hotness) در opt\-viewer نمایش داده شود. فایل‌های html حاصل در مرورگر اینترنت قابل مشاهده هستند. .SH "نحوه استفاده دستی از بخش‌های مجزای POLLY (HOW TO MANUALLY USE THE INDIVIDUAL PIECES OF POLLY)" .SS اجرای دستی گذرهای مجزای Polly .sp این مثال گذرهای (passes) مجزایی را که هنگام بهینه‌سازی کد با Polly دخیل هستند نشان می‌دهد. ما نحوه اجرای آن‌ها را به‌صورت تک‌به‌تک نمایش داده و برای هر یک توضیح می‌دهیم که چه تحلیلی انجام می‌گیرد یا چه تبدیلی اعمال می‌شود. در این مثال تبدیل چندوجهی توسط کاربر ارائه شده تا نشان داده شود که چه میزان بهبود کارایی را می‌توان از یک بهینه‌ساز خودکار ایدئال انتظار داشت. .SS 1. \fBایجاد LLVM\-IR از کد C\fP .INDENT 0.0 .INDENT 3.5 ابزار Polly روی LLVM\-IR کار می‌کند؛ از این رو لازم است فایل‌های منبع به LLVM\-IR ترجمه شوند. اگر قرار است بیش از یک فایل بهینه‌سازی شود، فایل‌ها را می‌توان با llvm\-link در یک فایل واحد ادغام نمود. .INDENT 0.0 .INDENT 3.5 .sp .EX clang \-S \-emit\-llvm matmul.c \-Xclang \-disable\-O0\-optnone \-o matmul.ll .EE .UNINDENT .UNINDENT .UNINDENT .UNINDENT.SS 2. \fBآماده‌سازی LLVM\-IR برای Polly\fP .INDENT 0.0 .INDENT 3.5 ابزار Polly تنها قادر است با کدهایی کار کند که با یک فرم متعارف (canonical form) مطابقت داشته باشند. برای تبدیل LLVM\-IR به این فرم، از مجموعه‌ای از گذرهای متعارف‌سازی (canonicalization passes) استفاده می‌کنیم. این گذرها با استفاده از \(aq\-polly\-canonicalize\(aq زمان‌بندی و اجرا می‌شوند. .INDENT 0.0 .INDENT 3.5 .sp .EX opt \-S \-polly\-canonicalize matmul.ll \-o matmul.preopt.ll .EE .UNINDENT .UNINDENT .UNINDENT .UNINDENT .SS 3. \fBنمایش SCoPهای شناسایی‌شده توسط Polly (اختیاری)\fP .INDENT 0.0 .INDENT 3.5 برای بررسی اینکه آیا Polly قادر به شناسایی SCoPها بوده است یا خیر، ساختار SCoPهای شناسایی‌شده را چاپ می‌کنیم. در مثال ما دو SCoP شناسایی شده است؛ یکی در \(aqinit_array\(aq و دیگری در \(aqmain\(aq. .INDENT 0.0 .INDENT 3.5 .sp .EX $ opt \-basic\-aa \-polly\-ast \-analyze matmul.preopt.ll \-polly\-process\-unprofitable \-polly\-use\-llvm\-names .EE .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .EX :: isl ast :: init_array :: %for.cond1.preheader\-\-\-%for.end19 if (1) for (int c0 = 0; c0 <= 1535; c0 += 1) for (int c1 = 0; c1 <= 1535; c1 += 1) Stmt_for_body3(c0, c1); else { /* original code */ } :: isl ast :: main :: %for.cond1.preheader\-\-\-%for.end30 if (1) for (int c0 = 0; c0 <= 1535; c0 += 1) for (int c1 = 0; c1 <= 1535; c1 += 1) { Stmt_for_body3(c0, c1); for (int c2 = 0; c2 <= 1535; c2 += 1) Stmt_for_body8(c0, c1, c2); } else { /* original code */ } .EE .UNINDENT .UNINDENT .UNINDENT .UNINDENT .SS 4. \fBبرجسته‌سازی SCoPهای شناسایی‌شده در CFGهای برنامه (نیازمند graphviz/dotty)\fP .INDENT 0.0 .INDENT 3.5 ابزار Polly می‌تواند از graphviz برای نمایش گرافیکی یک CFG استفاده کند که در آن SCoPهای شناسایی‌شده برجسته شده‌اند. همچنین می‌تواند فایل‌های \(aq.dot\(aq ایجاد کند که می‌توان آن‌ها را با استفاده از ابزار \(aqdot\(aq به قالب‌های گرافیکی گوناگون تبدیل نمود. .INDENT 0.0 .INDENT 3.5 .sp .EX $ opt \-polly\-use\-llvm\-names \-basic\-aa \-view\-scops \-disable\-output matmul.preopt.ll $ opt \-polly\-use\-llvm\-names \-basic\-aa \-view\-scops\-only \-disable\-output matmul.preopt.ll .EE .UNINDENT .UNINDENT .sp خروجی برای توابع مختلف: .INDENT 0.0 .IP \(bu 2 view\-scops : main \%, init_array \%, print_array \% .IP \(bu 2 view\-scops\-only : main\-scopsonly \%, init_array\-scopsonly \%, print_array\-scopsonly \% .UNINDENT .UNINDENT .UNINDENT.SS 5. \fBمشاهده نمایش چندوجهی SCoPها\fP .INDENT 0.0 .INDENT 3.5 .INDENT 0.0 .INDENT 3.5 .sp .EX $ opt \-polly\-use\-llvm\-names \-basic\-aa \-polly\-scops \-analyze matmul.preopt.ll \-polly\-process\-unprofitable .EE .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .EX [...]Printing analysis \(aqPolly \- Create polyhedral description of Scops\(aq for region: \(aqfor.cond1.preheader => for.end19\(aq in function \(aqinit_array\(aq: Function: init_array Region: %for.cond1.preheader\-\-\-%for.end19 Max Loop Depth: 2 Invariant Accesses: { } Context: { : } Assumed Context: { : } Invalid Context: { : 1 = 0 } Arrays { float MemRef_A[*][1536]; // Element size 4 float MemRef_B[*][1536]; // Element size 4 } Arrays (Bounds as pw_affs) { float MemRef_A[*][ { [] \-> [(1536)] } ]; // Element size 4 float MemRef_B[*][ { [] \-> [(1536)] } ]; // Element size 4 } Alias Groups (0): n/a Statements { Stmt_for_body3 Domain := { Stmt_for_body3[i0, i1] : 0 <= i0 <= 1535 and 0 <= i1 <= 1535 }; Schedule := { Stmt_for_body3[i0, i1] \-> [i0, i1] }; MustWriteAccess := [Reduction Type: NONE] [Scalar: 0] { Stmt_for_body3[i0, i1] \-> MemRef_A[i0, i1] }; MustWriteAccess := [Reduction Type: NONE] [Scalar: 0] { Stmt_for_body3[i0, i1] \-> MemRef_B[i0, i1] }; } [...]Printing analysis \(aqPolly \- Create polyhedral description of Scops\(aq for region: \(aqfor.cond1.preheader => for.end30\(aq in function \(aqmain\(aq: Function: main Region: %for.cond1.preheader\-\-\-%for.end30 Max Loop Depth: 3 Invariant Accesses: { } Context: { : } Assumed Context: { : } Invalid Context: { : 1 = 0 } Arrays { float MemRef_C[*][1536]; // Element size 4 float MemRef_A[*][1536]; // Element size 4 float MemRef_B[*][1536]; // Element size 4 } Arrays (Bounds as pw_affs) { float MemRef_C[*][ { [] \-> [(1536)] } ]; // Element size 4 float MemRef_A[*][ { [] \-> [(1536)] } ]; // Element size 4 float MemRef_B[*][ { [] \-> [(1536)] } ]; // Element size 4 } Alias Groups (0): n/a Statements { Stmt_for_body3 Domain := { Stmt_for_body3[i0, i1] : 0 <= i0 <= 1535 and 0 <= i1 <= 1535 }; Schedule := { Stmt_for_body3[i0, i1] \-> [i0, i1, 0, 0] }; MustWriteAccess := [Reduction Type: NONE] [Scalar: 0] { Stmt_for_body3[i0, i1] \-> MemRef_C[i0, i1] }; Stmt_for_body8 Domain := { Stmt_for_body8[i0, i1, i2] : 0 <= i0 <= 1535 and 0 <= i1 <= 1535 and 0 <= i2 <= 1535 }; Schedule := { Stmt_for_body8[i0, i1, i2] \-> [i0, i1, 1, i2] }; ReadAccess := [Reduction Type: NONE] [Scalar: 0] { Stmt_for_body8[i0, i1, i2] \-> MemRef_C[i0, i1] }; ReadAccess := [Reduction Type: NONE] [Scalar: 0] { Stmt_for_body8[i0, i1, i2] \-> MemRef_A[i0, i2] }; ReadAccess := [Reduction Type: NONE] [Scalar: 0] { Stmt_for_body8[i0, i1, i2] \-> MemRef_B[i2, i1] }; MustWriteAccess := [Reduction Type: NONE] [Scalar: 0] { Stmt_for_body8[i0, i1, i2] \-> MemRef_C[i0, i1] }; } .EE .UNINDENT .UNINDENT .UNINDENT .UNINDENT.SS 6. \fBنمایش وابستگی‌ها برای SCoPها\fP .INDENT 0.0 .INDENT 3.5 .INDENT 0.0 .INDENT 3.5 .sp .EX $ opt \-basic\-aa \-polly\-use\-llvm\-names \-polly\-dependences \-analyze matmul.preopt.ll \-polly\-process\-unprofitable .EE .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .EX [...]Printing analysis \(aqPolly \- Calculate dependences\(aq for region: \(aqfor.cond1.preheader => for.end19\(aq in function \(aqinit_array\(aq: RAW dependences: { } WAR dependences: { } WAW dependences: { } Reduction dependences: n/a Transitive closure of reduction dependences: { } [...]Printing analysis \(aqPolly \- Calculate dependences\(aq for region: \(aqfor.cond1.preheader => for.end30\(aq in function \(aqmain\(aq: RAW dependences: { Stmt_for_body3[i0, i1] \-> Stmt_for_body8[i0, i1, 0] : 0 <= i0 <= 1535 and 0 <= i1 <= 1535; Stmt_for_body8[i0, i1, i2] \-> Stmt_for_body8[i0, i1, 1 + i2] : 0 <= i0 <= 1535 and 0 <= i1 <= 1535 and 0 <= i2 <= 1534 } WAR dependences: { } WAW dependences: { Stmt_for_body3[i0, i1] \-> Stmt_for_body8[i0, i1, 0] : 0 <= i0 <= 1535 and 0 <= i1 <= 1535; Stmt_for_body8[i0, i1, i2] \-> Stmt_for_body8[i0, i1, 1 + i2] : 0 <= i0 <= 1535 and 0 <= i1 <= 1535 and 0 <= i2 <= 1534 } Reduction dependences: n/a Transitive closure of reduction dependences: { } .EE .UNINDENT .UNINDENT .UNINDENT .UNINDENT .SS 7. \fBبرون‌بری فایل‌های jscop\fP .INDENT 0.0 .INDENT 3.5 .INDENT 0.0 .INDENT 3.5 .sp .EX $ opt \-basic\-aa \-polly\-use\-llvm\-names \-polly\-export\-jscop matmul.preopt.ll \-polly\-process\-unprofitable .EE .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .EX [...]Writing JScop \(aq%for.cond1.preheader\-\-\-%for.end19\(aq in function \(aqinit_array\(aq to \(aq./init_array___%for.cond1.preheader\-\-\-%for.end19.jscop\(aq. Writing JScop \(aq%for.cond1.preheader\-\-\-%for.end30\(aq in function \(aqmain\(aq to \(aq./main___%for.cond1.preheader\-\-\-%for.end30.jscop\(aq. .EE .UNINDENT .UNINDENT .UNINDENT .UNINDENT .SS 8. \fBدرون‌ریزی فایل‌های تغییریافتهٔ jscop و چاپ ساختار به‌روزشدهٔ SCoP (اختیاری)\fP .INDENT 0.0 .INDENT 3.5 ابزار Polly می‌تواند فایل‌های jscop را که در آن‌ها زمان‌بندی دستورها تغییر یافته است، مجدداً درون‌ریزی کند. این زمان‌بندی‌های تغییریافته برای توصیف تبدیل‌ها به کار می‌روند. می‌توان با مشخص کردن پسوند فایل jscop مورد نظر، فایل‌های jscop متفاوتی را درون‌ریزی کرد. .sp ما سه تبدیل مختلف را روی SCoP در تابع main اعمال می‌کنیم. فایل‌های jscop توصیف‌کننده این تبدیل‌ها به‌صورت دستی نوشته شده‌اند (و در docs/experiments/matmul در دسترس هستند). .sp \fBبدون Polly\fP .sp به‌عنوان مبنا، هیچ تولید کدی با Polly فراخوانی نمی‌کنیم، بلکه تنها بهینه‌سازی‌های معمول \-O3 را اعمال می‌کنیم. .INDENT 0.0 .INDENT 3.5 .sp .EX $ opt \-basic\-aa \-polly\-use\-llvm\-names matmul.preopt.ll \-polly\-import\-jscop \-polly\-ast \-analyze \-polly\-process\-unprofitable .EE .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .EX [...] :: isl ast :: main :: %for.cond1.preheader\-\-\-%for.end30 if (1) for (int c0 = 0; c0 <= 1535; c0 += 1) for (int c1 = 0; c1 <= 1535; c1 += 1) { Stmt_for_body3(c0, c1); for (int c3 = 0; c3 <= 1535; c3 += 1) Stmt_for_body8(c0, c1, c3); } else { /* original code */ } [...] .EE .UNINDENT .UNINDENT .sp \fBجابه‌جایی حلقه (و شکافت حلقه برای امکان‌پذیر ساختن جابه‌جایی)\fP .sp ما حلقه‌ها را می‌شکافیم و اکنون می‌توانیم ابعاد حلقه‌ای را که Stmt_for_body8 را شمارش می‌کنند جابه‌جا کنیم. .INDENT 0.0 .INDENT 3.5 .sp .EX $ opt \-basic\-aa \-polly\-use\-llvm\-names matmul.preopt.ll \-polly\-import\-jscop \-polly\-import\-jscop\-postfix=interchanged \-polly\-ast \-analyze \-polly\-process\-unprofitable .EE .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .EX [...] :: isl ast :: main :: %for.cond1.preheader\-\-\-%for.end30 if (1) { for (int c1 = 0; c1 <= 1535; c1 += 1) for (int c2 = 0; c2 <= 1535; c2 += 1) Stmt_for_body3(c1, c2); for (int c1 = 0; c1 <= 1535; c1 += 1) for (int c2 = 0; c2 <= 1535; c2 += 1) for (int c3 = 0; c3 <= 1535; c3 += 1) Stmt_for_body8(c1, c3, c2); } else { /* original code */ } [...] .EE .UNINDENT .UNINDENT .sp \fBجابه‌جایی + کاشی‌کاری (Tiling)\fP .sp علاوه بر جابه‌جایی، اکنون دومین آشیانهٔ حلقه را کاشی‌کاری می‌کنیم. .INDENT 0.0 .INDENT 3.5 .sp .EX $ opt \-basic\-aa \-polly\-use\-llvm\-names matmul.preopt.ll \-polly\-import\-jscop \-polly\-import\-jscop\-postfix=interchanged+tiled \-polly\-ast \-analyze \-polly\-process\-unprofitable .EE .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .EX [...] :: isl ast :: main :: %for.cond1.preheader\-\-\-%for.end30 if (1) { for (int c1 = 0; c1 <= 1535; c1 += 1) for (int c2 = 0; c2 <= 1535; c2 += 1) Stmt_for_body3(c1, c2); for (int c1 = 0; c1 <= 1535; c1 += 64) for (int c2 = 0; c2 <= 1535; c2 += 64) for (int c3 = 0; c3 <= 1535; c3 += 64) for (int c4 = c1; c4 <= c1 + 63; c4 += 1) for (int c5 = c3; c5 <= c3 + 63; c5 += 1) for (int c6 = c2; c6 <= c2 + 63; c6 += 1) Stmt_for_body8(c4, c6, c5); } else { /* original code */ } [...] .EE .UNINDENT .UNINDENT.sp \fBجابه‌جایی + کاشی‌کاری + قطعه‌بندی (Strip\-mining) جهت آماده‌سازی برداری‌سازی\fP .sp برای این‌که بعداً برداری‌سازی امکان‌پذیر شود، یک حلقه که اصطلاحاً به‌سادگی موازی‌پذیر (trivially parallelizable) است ایجاد می‌کنیم. این حلقه در درونی‌ترین سطح قرار دارد، موازی است و تنها ۴ تکرار دارد. این حلقه می‌تواند با دستورالعمل‌های ۴\-عنصری SIMD جایگزین شود. .INDENT 0.0 .INDENT 3.5 .sp .EX $ opt \-basic\-aa \-polly\-use\-llvm\-names matmul.preopt.ll \-polly\-import\-jscop \-polly\-import\-jscop\-postfix=interchanged+tiled \-polly\-ast \-analyze \-polly\-process\-unprofitable .EE .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .EX [...] :: isl ast :: main :: %for.cond1.preheader\-\-\-%for.end30 if (1) { for (int c1 = 0; c1 <= 1535; c1 += 1) for (int c2 = 0; c2 <= 1535; c2 += 1) Stmt_for_body3(c1, c2); for (int c1 = 0; c1 <= 1535; c1 += 64) for (int c2 = 0; c2 <= 1535; c2 += 64) for (int c3 = 0; c3 <= 1535; c3 += 64) for (int c4 = c1; c4 <= c1 + 63; c4 += 1) for (int c5 = c3; c5 <= c3 + 63; c5 += 1) for (int c6 = c2; c6 <= c2 + 63; c6 += 4) for (int c7 = c6; c7 <= c6 + 3; c7 += 1) Stmt_for_body8(c4, c7, c5); } else { /* original code */ } [...] .EE .UNINDENT .UNINDENT .UNINDENT .UNINDENT .SS 9. \fBتولید کد برای SCoPها (Codegenerate the SCoPs)\fP .INDENT 0.0 .INDENT 3.5 این عمل، کد جدیدی برای SCoPهای شناسایی‌شده توسط polly تولید می‌کند. در صورت وجود \-polly\-import\-jscop، تبدیلات مشخص‌شده در فایل‌های jscop واردشده اعمال خواهند شد. .INDENT 0.0 .INDENT 3.5 .sp .EX $ opt \-S matmul.preopt.ll | opt \-S \-O3 \-o matmul.normalopt.ll .EE .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .EX $ opt \-S matmul.preopt.ll \-basic\-aa \-polly\-use\-llvm\-names \-polly\-import\-jscop \-polly\-import\-jscop\-postfix=interchanged \-polly\-codegen \-polly\-process\-unprofitable | opt \-S \-O3 \-o matmul.polly.interchanged.ll .EE .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .EX Reading JScop \(aq%for.cond1.preheader\-\-\-%for.end19\(aq in function \(aqinit_array\(aq from \(aq./init_array___%for.cond1.preheader\-\-\-%for.end19.jscop.interchanged\(aq. File could not be read: No such file or directory Reading JScop \(aq%for.cond1.preheader\-\-\-%for.end30\(aq in function \(aqmain\(aq from \(aq./main___%for.cond1.preheader\-\-\-%for.end30.jscop.interchanged\(aq. .EE .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .EX $ opt \-S matmul.preopt.ll \-basic\-aa \-polly\-use\-llvm\-names \-polly\-import\-jscop \-polly\-import\-jscop\-postfix=interchanged+tiled \-polly\-codegen \-polly\-process\-unprofitable | opt \-S \-O3 \-o matmul.polly.interchanged+tiled.ll .EE .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .EX Reading JScop \(aq%for.cond1.preheader\-\-\-%for.end19\(aq in function \(aqinit_array\(aq from \(aq./init_array___%for.cond1.preheader\-\-\-%for.end19.jscop.interchanged+tiled\(aq. File could not be read: No such file or directory Reading JScop \(aq%for.cond1.preheader\-\-\-%for.end30\(aq in function \(aqmain\(aq from \(aq./main___%for.cond1.preheader\-\-\-%for.end30.jscop.interchanged+tiled\(aq. .EE .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .EX $ opt \-S matmul.preopt.ll \-basic\-aa \-polly\-use\-llvm\-names \-polly\-import\-jscop \-polly\-import\-jscop\-postfix=interchanged+tiled+vector \-polly\-codegen \-polly\-vectorizer=polly \-polly\-process\-unprofitable | opt \-S \-O3 \-o matmul.polly.interchanged+tiled+vector.ll .EE .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .EX Reading JScop \(aq%for.cond1.preheader\-\-\-%for.end19\(aq in function \(aqinit_array\(aq from \(aq./init_array___%for.cond1.preheader\-\-\-%for.end19.jscop.interchanged+tiled+vector\(aq. File could not be read: No such file or directory Reading JScop \(aq%for.cond1.preheader\-\-\-%for.end30\(aq in function \(aqmain\(aq from \(aq./main___%for.cond1.preheader\-\-\-%for.end30.jscop.interchanged+tiled+vector\(aq. .EE .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .EX $ opt \-S matmul.preopt.ll \-basic\-aa \-polly\-use\-llvm\-names \-polly\-import\-jscop \-polly\-import\-jscop\-postfix=interchanged+tiled+vector \-polly\-codegen \-polly\-vectorizer=polly \-polly\-parallel \-polly\-process\-unprofitable | opt \-S \-O3 \-o matmul.polly.interchanged+tiled+openmp.ll .EE .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .EX Reading JScop \(aq%for.cond1.preheader\-\-\-%for.end19\(aq in function \(aqinit_array\(aq from \(aq./init_array___%for.cond1.preheader\-\-\-%for.end19.jscop.interchanged+tiled+vector\(aq. File could not be read: No such file or directory Reading JScop \(aq%for.cond1.preheader\-\-\-%for.end30\(aq in function \(aqmain\(aq from \(aq./main___%for.cond1.preheader\-\-\-%for.end30.jscop.interchanged+tiled+vector\(aq. .EE .UNINDENT .UNINDENT .UNINDENT .UNINDENT.SS 10. \fBساخت فایل‌های اجرایی\fP .INDENT 0.0 .INDENT 3.5 .INDENT 0.0 .INDENT 3.5 .sp .EX $ llc matmul.normalopt.ll \-o matmul.normalopt.s \-relocation\-model=pic $ gcc matmul.normalopt.s \-o matmul.normalopt.exe $ llc matmul.polly.interchanged.ll \-o matmul.polly.interchanged.s \-relocation\-model=pic $ gcc matmul.polly.interchanged.s \-o matmul.polly.interchanged.exe $ llc matmul.polly.interchanged+tiled.ll \-o matmul.polly.interchanged+tiled.s \-relocation\-model=pic $ gcc matmul.polly.interchanged+tiled.s \-o matmul.polly.interchanged+tiled.exe $ llc matmul.polly.interchanged+tiled+vector.ll \-o matmul.polly.interchanged+tiled+vector.s \-relocation\-model=pic $ gcc matmul.polly.interchanged+tiled+vector.s \-o matmul.polly.interchanged+tiled+vector.exe $ llc matmul.polly.interchanged+tiled+vector+openmp.ll \-o matmul.polly.interchanged+tiled+vector+openmp.s \-relocation\-model=pic $ gcc matmul.polly.interchanged+tiled+vector+openmp.s \-lgomp \-o matmul.polly.interchanged+tiled+vector+openmp.exe .EE .UNINDENT .UNINDENT .UNINDENT .UNINDENT .SS 11. \fBمقایسه زمان اجرای فایل‌های اجرایی\fP .INDENT 0.0 .INDENT 3.5 با مقایسهٔ زمان اجرای قطعه‌کدهای مختلف مشاهده می‌کنیم که یک جابه‌جایی سادهٔ حلقه (loop interchange) در اینجا بیشترین افزایش کارایی را به همراه دارد. با این حال در این مورد، افزودن برداری‌سازی (vectorization) و استفاده از OpenMP کارایی را کاهش می‌دهد. .INDENT 0.0 .INDENT 3.5 .sp .EX $ time ./matmul.normalopt.exe real 0m11.295s user 0m11.288s sys 0m0.004s $ time ./matmul.polly.interchanged.exe real 0m0.988s user 0m0.980s sys 0m0.008s $ time ./matmul.polly.interchanged+tiled.exe real 0m0.830s user 0m0.816s sys 0m0.012s $ time ./matmul.polly.interchanged+tiled+vector.exe real 0m5.430s user 0m5.424s sys 0m0.004s $ time ./matmul.polly.interchanged+tiled+vector+openmp.exe real 0m3.184s user 0m11.972s sys 0m0.036s .EE .UNINDENT .UNINDENT .UNINDENT .UNINDENT .SH "نکات و ترفندهای استفاده و مشارکت در POLLY (TIPS AND TRICKS ON USING AND CONTRIBUTING TO POLLY)" .SS ارسال تغییرات (Commit) به شاخه اصلی polly .INDENT 0.0 .INDENT 3.5 .INDENT 0.0 .IP \(bu 2 مرجع عمومی برای گردش‌کار git\-svn \% .UNINDENT .UNINDENT .UNINDENT .SS استفاده از bugpoint برای ردگیری خطاها در فایل‌های حجیم .INDENT 0.0 .INDENT 3.5 اگر از نحوه فراخوانی \fBopt\fP آگاهید و فایل \fB\&.ll\fP بزرگی دارید که باعث بروز خطا می‌شود، \fBbugpoint\fP به شما امکان می‌دهد اندازه موارد آزمایشی را کاهش دهید. .sp الگوی کلی فراخوانی بدین صورت است: .INDENT 0.0 .IP \(bu 2 \fB$ bugpoint \-opt\-args \fP .UNINDENT .sp یک نمونه فراخوانی: .INDENT 0.0 .IP \(bu 2 \fB$ bugpoint crash.ll \-polly\-codegen \-opt\-args \-polly\-canonicalize \-polly\-process\-unprofitable\fP .UNINDENT .sp برای مستندات بیشتر درباره bugpoint، به راهنمای LLVM مراجعه کنید \% .UNINDENT .UNINDENT.SS تشخیص اینکه کدام گذر تغییر خاصی را ایجاد می‌کند .INDENT 0.0 .INDENT 3.5 اگر می‌دانید که دستوری مانند \fIopt \-O3 \-polly\fP تغییری ایجاد می‌کند، اما مایلید گذری را که آن تغییر را اعمال کرده است تفکیک کنید، مراحل به شرح زیر است: .INDENT 0.0 .IP \(bu 2 دستور \fB$ bugpoint \-O3 file.ll \-opt\-args \-polly\fP به bugpoint امکان می‌دهد گذری را که موجب فروپاشی (crash) می‌شود پیدا کند. .UNINDENT .sp برای انجام دستی این کار: .INDENT 0.0 .IP \(bu 2 دستور \fB$ opt \-O3 \-polly \-debug\-pass=Arguments\fP را اجرا کنید تا تمام گذرهایی که به‌طور پیش‌فرض اجرا می‌شوند را دریافت کنید. گزینهٔ \fB\-debug\-pass=Arguments\fP تمام گذرهای اجراشده را فهرست خواهد کرد. .IP \(bu 2 با روش تنصیف (bisect) تا رسیدن به گذری که تغییر را اعمال می‌کند پیش بروید. .UNINDENT .UNINDENT .UNINDENT .SS اشکال‌زدایی پس‌رفت‌هایی که در نقطه‌ای نامشخص در گذشته رخ داده‌اند .sp در صورت بروز پس‌رفت در کارایی یا صحت عملکرد (برای نمونه، نسخهٔ قبلی Polly طبق انتظار عمل می‌کرد ولی نسخهٔ جدیدتر دچار مشکل شده است)، اجرای تنصیف (bisect) در طول تاریخچهٔ نسخه‌ها، روش استاندارد برای شناسایی کامیتی است که این پس‌رفت را ایجاد کرده است. .sp پروژهٔ LLVM دارای یک مخزن واحد است که تمام پروژه‌ها را در بر می‌گیرد. این مخزن را می‌توان از این نشانی کلون کرد: \%\&. چگونگی اجرای bisect بر روی یک مخزن git در اینجا شرح داده شده است: \%\&. فرایند bisect همچنین می‌تواند به‌صورت خودکار انجام شود، همان‌طور که در اینجا توضیح داده شده است: \%\&. یک اسکریپت اجرای ویژهٔ LLVM نیز در اینجا در دسترس است: \%\&. .SH "کارایی (PERFORMANCE)" .SS ضرب ماتریسی تعمیم‌یافته با کارایی بالا .sp ابزار Polly به‌طور خودکار ضرب ماتریسی تعمیم‌یافته را شناسایی کرده و بهینه‌سازی می‌کند؛ محاسبات C ← α ⊗ C ⊕ β ⊗ A ⊗ B، که در آن A و B و C سه ماتریس با اندازهٔ متناسب هستند، عملگرهای ⊕ و ⊗ از نیم‌حلقهٔ ماتریسی متناظر سرچشمه می‌گیرند، α و β مقادیر ثابت هستند، و بتا با صفر برابر نیست. این کار امکان دستیابی به ساختاری بسیار بهینه‌شده، مشابه پیاده‌سازی حرفه‌ای GEMM که در GotoBLAS و جانشینان آن یافت می‌شود را فراهم می‌سازد. ارزیابی کارایی GEMM در شکل زیر نشان داده شده است. .INDENT 0.0 .INDENT 3.5 [تصویر] .UNINDENT .UNINDENT .SS تأثیر Polly بر زمان کامپایل .sp مجموعهٔ Clang+LLVM+Polly با استفاده از Clang روی سیستمی مبتنی بر پردازندهٔ Intel(R) Core(TM) i7\-7700 کامپایل شده‌اند. این آزمایش دو بار تکرار شده است: یک بار با فعال بودن Polly و یک بار بدون آن، تا تأثیر آن بر زمان کامپایل اندازه‌گیری شود. .sp نسخه‌های زیر مورد استفاده قرار گرفته‌اند: .INDENT 0.0 .IP \(bu 2 Polly (هش گیت 0db98a4837b6f233063307bb9184374175401922) .IP \(bu 2 Clang (هش گیت 3e1d04a92b51ed36163995c96c31a0e4bbb1561d) .IP \(bu 2 LLVM (هش گیت 0265ec7ebad69a47f5c899d95295b5eb41aba68e) .UNINDENT .sp از سامانهٔ ساخت ninja \% استفاده شده است. .sp برای هر دو حالت، کل فرایند کامپایل پنج بار تکرار شد. زمان‌های کامپایل بر حسب ثانیه در جدول زیر آمده است. .TS box center; l|l. T{ Polly غیرفعال T} T{ Polly فعال T} _ T{ 964 T} T{ 977 T} _ T{ 964 T} T{ 980 T} _ T{ 967 T} T{ 981 T} _ T{ 967 T} T{ 981 T} _ T{ 968 T} T{ 982 T} .TE .sp میانهٔ زمان کامپایل بدون فعال بودن Polly برابر ۹۶۷ ثانیه و با فعال بودن Polly برابر ۹۸۱ ثانیه است. میزان سربار ۱٫۴٪ است. .INDENT 0.0 .IP \(bu 2 فهرستی از گذرهای Polly \% .UNINDENT .INDENT 0.0 .IP \(bu 2 نمایه \%<> .IP \(bu 2 صفحهٔ جستجو \%<> .UNINDENT.SH "نویسنده (AUTHOR)" نام نویسنده تعیین نشده است .SH "کپی‌رایت و تکثیر (COPYRIGHT)" 2010-2026، تیم Polly .\" End of generated man page.