ما Doom اصلی را به SQL پورت کردیم
آدرس مقاله: https://cedardb.com/blog/sqldoom/ آدرس نظرات: https://news.ycombinator.com/item?id=49948300 امتیاز: 162 # نظرات: 22
TL;DR: ما منطق و رندر اصلی بازی Doom 1993 را به SQL منتقل کردیم و آن را در یک پایگاه داده اجرا کردیم. حلقه بازی با سرعت 35 فریم در ثانیه اصلی اجرا می شود، در حالی که رندر بافر کامل فریم 320x200 را تا حداکثر 60 هرتز در لپ تاپ من تولید می کند. پایتون فقط زمانبندی را کنترل میکند، صفحهکلید را میخواند و نقشه بیتی را که برمیگرداند نمایش میدهد. چند نفره نیز کار می کند.
میتوانید همین حالا Deathmatch را بازی کنید، چهار اسلات، اول از همه.
این نسخه اشتراکافزار قسمت اول است. اگر همه صندلی ها گرفته شوند، در صف فرود می آیید. اگر صف پر است، همچنان میتوانید در حین انتظار، وضعیت بازی را از طریق SQL جستجو کنید.
سال گذشته، DOOMQL [Github] را منتشر کردم. برخی از هنرهای ASCII تقریبا شبیه Doom در 30 فریم بر ثانیه بود و مردم آن را بسیار دوست داشتند. اما برخی از افراد به درستی اشاره کردند که به Wolfenstein 3D بسیار نزدیکتر از Doom است، زیرا از رویکرد raycasting استفاده می کند. از سوی دیگر، Doom از درختهای BSP استفاده میکند که سفارش عمق صحیح را به اندازه کافی ارزان میکند تا بافتها، زوایای دلخواه دیوار و ارتفاعهای مختلف کف را تامین کند.
خب، من نمیتوانم اجازه بدهم این کار آرام بگیرد و بعد از کمی سرهمبندی (حدس زدید، دوباره مرخصی والدینی)، بالاخره میتوانم Doom واقعی را که به طور کامل در SQL اجرا میشود، ارائه کنم.
بیایید ابتدا چند قانون پایه در مورد آنچه می خواهیم به دست آوریم ایجاد کنیم:
پایتون عمدا خسته کننده است (قانون 5). یک اسکریپت واحد از pygame برای هدایت ورودی، ترسیم بیت مپ خروجی و راهاندازی تیک بازی 35 بار در ثانیه استفاده میکند. منطق بازی، حالت بازی و رندر در داخل پایگاه داده زنده هستند.
این دو مسیر عمدا از هم جدا هستند: منطق بازی روی یک حلقه ثابت 35 هرتز اجرا میشود، در حالی که رندر تابعی خالص از جداول حالت بازی است و مشتری میتواند هر زمان که بخواهد یک فریم جدید بخواهد (یعنی تا حد امکان سریع و اغلب).
به راحتی، فرمت فایل .wad Doom در واقع در حال حاضر بسیار رابطه ای است.
دو راس توسط یک LINEDEF که دارای دو SIDEDEF است به هم متصل می شوند. SIDEDEF یک بخش را محدود کرد که می تواند چیزهایی را در خود داشته باشد، شما این ایده را دریافت می کنید. ترجمه کل WAD به یک پایگاه داده به طرز شگفت آوری ساده بود و حدود 1000 خط پایتون را به خود اختصاص داد. وارد کردن تمام Doom 1 در لپ تاپ من حدود 18 ثانیه طول می کشد.
به عنوان مثال، در اینجا یک پرس و جو ارائه شده است که E1M1 را از دید پرنده ارائه می کند:
برای من مهم بود که Doom را در واقع پورت کنم، نه تنها فریم هایی را که به طور مبهم شبیه آن هستند رندر کنم. البته، بصری نقش مهمی در آن دارد، اما بازی Doom نیز بسیار جذاب است. به صحنه زیر که قانون 2 در عمل است (من در حال تفریح هستم) نگاه کنید:
همانطور که می بینید، چیزهای زیادی در جریان است. فقط در این کلیپ کوتاه می بینیم:
و ما زمان زیادی برای پردازش همه آن نداریم: Doom اصلی روی یک ساعت ثابت 35 هرتز اجرا میشد، بنابراین یک تیک دارای بودجه 1000 میلیثانیه × 35 هرتز = 28.6 میلیثانیه است. همچنین دقیقا یک فریم در هر تیک میکشید، بنابراین روی 35 FPS نیز محدود میشد.
SQLDoom منطق بازی را روی 35 هرتز نگه میدارد (بنابراین همه ثابتهای اصلی هنوز کار میکنند)، اما ترسیم را جدا میکند. کلاینت می تواند هر زمان که بخواهد یک فریم را جستجو کند (دریافت کند؟) و ما موقعیت دوربین را بین تیک ها درون یابی می کنیم. بنابراین دو بودجه وجود دارد که باید از آنها مراقبت کنیم:
تیک های بازی ذاتا رویه ای هستند. ما هر بار که تیک را اجرا می کنیم دنباله ای از کارهایی داریم که باید انجام دهیم. CedarDB دارای یک زبان برنامه نویسی به نام cedarscript است، این زبان شباهت زیادی به PL/pgSQL دارد و به ما امکان می دهد قبل از هر کاری برنامه ریزی کنیم.
درایور پایتون از بالا هر 1/35 ثانیه SELECT doom_run_game_tic(...) را فراخوانی می کند.
سپس هر کدام از توابع نامیده می شوند دسته ای از دستورات SQL را اجرا می کنند. در زیر بخشی از ماشین حالت هوش مصنوعی هیولا را مشاهده می کنید.
همانطور که می بینید، رفتار کلیپ بالا را رمزگذاری می کند: اگر دشمن به شدت آسیب وارد کند (مورد زمانی که d.health < -d.max_health و d.xdeath_frame IS NOT NULL باشد) به شدت منفجر می شود! (سپس 'xdeath'::actor_state).
این در واقع کندترین تیک بازی است که توانستم پیدا کنم. این در سطح E4M1 با 46 هیولای بیدار است که همه سعی می کنند از دری که در حال حاضر باز می شود به سمت من هجوم آورند. 10.45 میلی ثانیه طول می کشد، بنابراین 37٪ از بودجه تیک موجود.
یک تیک معمولی تر با 6 هیولا بیدار به طور متوسط 2.15 میلی ثانیه یا حدود 8 درصد از بودجه زمان می برد. فضای زیادی برای سر گذاشتن!
صادقانه بگویم، من شگفت زده شدم که چگونه می توان منطق بسیار پیچیده بازی را در SQL بیان کرد. منطق بازی فقط 5900 خط SQL است. در حالی که این بسیار به نظر می رسد، قطعا کمتر از کد منبع اصلی C است که در حدود 9000 خط همین کار را انجام می دهد!
همچنین، شما را مجبور می کند متفاوت فکر کنید. به جای تکرار کردن، به عنوان مثال، دشمنان یک به یک، فقط یک شرط به روز رسانی ساده ... WHERE را بنویسید و به پایگاه داده اجازه دهید تا بفهمد که چگونه آن را به بهترین شکل اعمال کند - به طور موازی، به طور خودکار!
این همچنین باعث شد که الگوی Entity Component System (ECS) برای من کلیک کند. در اینجا، هر موجودیت (بازیکن، هیولا، چیز، …) دارای اجزای متعددی است (موقعیت، جن، آمار، …) و یک سیستم (هیولا ai، پخش کننده حرکت، محاسبه خسارت) درباره نحوه تعامل موجودیتها با مجموعه مشخصی از ویژگیها با یکدیگر تصمیم میگیرد. ECS در مورد محلی بودن داده ها و نحوه تکرار بر روی موجودیت هایی که مجموعه ای معین از مؤلفه ها دارند، بسیار است. خوب، در SQL ما بسیار به پردازش فشرده داده عادت داریم!
هر جزء تبدیل به جدول می شود و هر سیستم به یک به روز رسانی یا درج تبدیل می شود که فقط به جداول مورد نظر خود با موجودیت به عنوان کلید پیوست می پیوندد!
هر فریم فقط یک نمای غول پیکر است که هندسه سطح و وضعیت بازی به اضافه موقعیت بازیکن را به عنوان ورودی می خواند و یک فریم بافر کامل را برمی گرداند. در اینجا طرحی از کل خط لوله رندر آمده است:
پیاده سازی 1300 خط SQL (به استثنای نظرات) است که در 89 CTE پخش شده است، برای یک پرس و جوی SQL بسیار پیچیده است!
اما علیرغم اینکه دیوانگی کامل به نظر می رسد، این خط لوله در واقع به کاری که Doom انجام می دهد بسیار نزدیک است. SQL حتی یک مزیت دارد: منبع linux_doom از حدود 3300 خط (به استثنای نظرات) برای موتور رندر خود استفاده می کند. حدود 2.5 برابر خطوط بیشتر از SQLDoom. اینکه آیا در وهله اول ایده خوبی بود یا نه، یک سوال متفاوت است، و بعدا در مورد آن صحبت خواهیم کرد.
بیایید ابتدا به جالب ترین قسمت های خط لوله رندر نگاه کنیم:
نیمه سمت چپ حذف مبتنی بر bsp را نشان می دهد، نیمه سمت راست رندر دیوار و visplanes را به تصویر می کشد.
از آنجایی که در سال 1993 هیچکس پردازندههای گرافیکی با بافر Z شتابدهنده سختافزاری نداشت، Doom باید با ترسیم به ترتیب صحیح، انسداد را درست میکرد. روشی که Doom این کار را انجام میدهد بسیار مبتکرانه است: جلو به عقب نقاشی میکند و پیکسلهایی را که قبلا نقاشی کرده است پیگیری میکند (یعنی اگر قبلا یک پیکسل دیوار کشیدهام، مجبور نیستم هیولا را پشت آن بکشم). اما گفتن این کار آسان تر از انجام آن است: ما به روشی کارآمد نیاز داریم تا همه چیز را در سطح عمیق مرتب کنیم.
Doom این ترتیب را با استفاده از درختان BSP از پیش محاسبه شده در فایل doom.wad دریافت می کند. هر گره درخت یک خط است که نقشه را به دو قسمت تقسیم می کند. بنابراین بخشهای نقشه به زیربخشهای زیادی در دو طرف آن خطوط تقسیم میشوند و سپس به درخت وارد میشوند تا ویژگیهای زیر را به دست آوریم:
بنابراین با پیمایش بازگشتی درخت BSP، ترتیبی از جلو به پشت همه زیربخش ها را دریافت می کنیم. این ترتیب رندر را مستقیما به ما می دهد: هنگامی که یک منطقه صفحه توسط چیزی نزدیکتر پوشیده شد، اشیاء پشت آن را می توان نادیده گرفت.
در حال حرکت به این صورت است (شاید مجبور باشید آن را به صورت تمام صفحه مشاهده کنید): مرورگر شما از برچسب ویدیو پشتیبانی نمی کند.
در سمت چپ، زیربخش ها از جلو به عقب مرتب می شوند، در حالی که شاخه های BSP خارج از دید مشتاقانه حذف می شوند. در وسط می توانید ترتیبی که SQLDoom به هر منطقه اختصاص می دهد را مشاهده کنید. در سمت راست، قاب حاصل را میبینید که دیوارهای آن بر اساس زیربخشی که در آن قرار دارند رنگ شده است.
پانل میانی بهینهسازیای را نشان میدهد که SQLDoom انجام میدهد: برای عملکرد بهتر، همه مسیرها را در درخت BSP یک بار در زمان بارگذاری از قبل محاسبه میکنیم. برای یک موقعیت معین، هر قدم در طول چنین مسیری یا از جلو (کدگذاری شده با 0) یا عقب (با کد 1) است. اگر این تصمیمات را در یک بیگنت جمع کنیم و آن را از نظر واژگانی مرتب کنیم (ترتیب بر اساس)، ترتیب درستی از جلو به عقب خواهیم داشت.
One sum() ... order by جایگزین کل نزول بازگشتی می شود! 40 بیت همچنین باید بتواند هر نقشه ای را که به آن پرتاب می کنیم کنترل کند: عمیق ترین BSP-Tree مربوط به E4M8 است و فقط 32 سطح دارد. تا زمانی که نقشه های شما از 256 برابر بزرگ ترین نقشه وانیلی بزرگتر نباشد، همه چیز مرتب شده اید!
اگر با دقت نگاه کنید، میبینید که پیمایش bsp ما نیز حذف را انجام میدهد: بهراحتی، هر گره در .wad یک جعبه مرزی از همه فرزندان خود را نیز تعریف میکند. اگر بتوانیم ثابت کنیم که نمای frustum ما کاملا خارج از آن کادر محدود است، لازم نیست آن زیردرخت را برای رندر در نظر بگیریم - این همان چیزی است که visual_children.keep نشان می دهد. بنابراین bool_and(vc.keep) تمام زیربخشهایی را که هیچ اجدادی واجد شرایط نیست حذف میکند.
همه چیز بعد از آن در خط لوله فقط در برابر bsp_seq متصل می شود، بنابراین فقط زیربخش های قابل مشاهده در نظر گرفته می شوند و به ترتیب درست هستند.
Doom نوعی تقلب است، سه بعدی به نظر می رسد، اما در واقعیت یک بازی 2.5 بعدی است. اساسا فقط یک سطح صاف با دیوارها و سقف های کاملا عمودی است که همیشه موازی با زمین هستند. این رندر را بسیار آسان تر از یک موتور سه بعدی واقعی می کند:
یک دیوار مجموعهای از ستونهای صفحهنمایش بههم پیوسته را اشغال میکند و در داخل هر ستون، گسترهای از پیکسلها به هم پیوسته است. بنابراین میتوانیم دیوارها را یک به یک، جلو به عقب با گسترش سطرها و ستونها از طریق ()gene_series نقاشی کنیم:
Doom به جای آن از دو حلقه استفاده می کند: R_RenderSegLoop برای گرفتن ستون های صفحه و R_DrawColumn برای ترسیم پیکسل ها.
رندر دیوارها به طور متوسط 1.7 میلی ثانیه هزینه دارد.
اکنون که دیوارها از سر راهمان خارج شده است، بیایید در مورد قسمت سرگرم کننده صحبت کنیم: کف و سقف، چیزی که Doom آن را visplanes می نامد.
متأسفانه، الگوریتم رندر Doom تقریبا به SQL ترجمه نمی شود زیرا بسیار ضروری است: Doom دو آرایه، گیره سقفی و گیره کف را نگه می دارد که یک ورودی در هر ستون صفحه نمایش دارند. آنها نوار را در هر ستونی که هنوز باز است علامت گذاری می کنند (یعنی باید به کف یا سقف تبدیل شود و هنوز رنگ نشده است) هر زمان که یک دیوار جدید رنگ می شود، آنها جهش می یابند تا زمانی که هر پیکسل پر شود. Doom نه تنها آنها را جهش می دهد، بلکه بسیار مهم است که آنها را به ترتیب درست تغییر دهید. این مبتکرانه است!
در نهایت این فقط یک الگوریتم سیل پر است، اما همه چیز اساسا رایگان به نظر می رسد (یعنی در C).
SQLDoom باید به گونهای متفاوت به این مشکل برخورد کند، زیرا ما مفاهیم حلقهها یا حالت تغییرپذیر را در SQL نداریم. بنابراین به جای حلقه زدن، به مرتبسازی و جمعآوری آنهای مرتبشده روی میآوریم - حلقه یک مرد فقیر!
چیزهایی که در اینجا تکرار می کنیم پانل نامیده می شوند: یک قسمت از دیوار که در یک ستون از صفحه ظاهر می شود. برخی از پانلها چیزی را ترسیم میکنند: یک دیوار یکپارچه (جامد)، دیوار بالای در (بالا)، یا قسمت دیوار زیر پنجره یا یک جان پناه (پایین)، برخی از پانلها فقط برای تأثیرگذاری بر نحوه نمایش پانلهای دیگر وجود دارند: اگر از دری زیر بالکن خارج شوید، چیزی بالای سرتان وجود دارد و باید به جایی ختم شود.
بنابراین برای هر ستون صفحه (col_x) ما یک لیست مرتب از پانل ها از نزدیک به دور داریم. بنابراین وضعیت کلیپ قبل از پانل به طور کامل توسط ردیف قبل از آن تعریف می شود. آیا عملکردهای پنجره را بو می کنم؟
از آنجایی که توضیح آن در متن بسیار سخت است، اجازه دهید در عوض یک ویدیو تماشا کنیم! مرورگر شما از برچسب ویدیو پشتیبانی نمی کند.
ما ابتدا برای هر پانل در صحنه که به طور بالقوه برخی از پیکسل ها را ارائه می دهد محاسبه می کنیم که هنوز چه مقدار از ستون اختصاص داده نشده است. و تنها پیکسلهایی که قبلا میتوان به آنها اختصاص داد از همه پانلهای نزدیکتر هستند (این ردیفهای بین UNBUNDED PRECEDING و 1 PRECEDING عبارت در (1) است). سپس از انتهای پنل قبلی تا ابتدای پنل بعدی (2) چند پیکسل می کشیم. ما این کار را هم برای سقف و هم برای کف انجام می دهیم.
یک راه بسیار هک برای پنهان کردن یک الگوریتم ضروری به عنوان مبتنی بر مجموعه، درست است؟ خوب است که توابع پنجره…
رندر کف، سقف و آسمان معمولا حدود 3 میلیثانیه هزینه دارد.
متأسفانه، مجبور شدم به شما دروغ بگویم: دیوارها، ویسپلین ها و رزولوشن اسپرایت هنوز چیزی را ترسیم نمی کنند. آنها فقط نامزدهایی از فرم (x، y، عمق، رنگ) را با پیکسل های بالقوه زیادی در یک موقعیت، اما در اعماق متفاوت منتشر می کنند: از آنجایی که ما حساب نقطه ثابت Doom را اجرا نمی کنیم، می توانیم دیوارها، کف ها و آسمان های مختلفی با هم همپوشانی داشته باشند. همچنین، ما باید اسپرایت ها را رندر کنیم که به نوبه خود می توانند تا حدی توسط دیوارها مسدود شوند. Doom یک رقص کاملا فشرده انجام می دهد تا مطمئن شود که هرگز این اتفاق نمی افتد، بنابراین آنها مجبور به انجام z-buffering نباشند.
من سعی کردم و نتوانستم آن رقص را در SQL بازتولید کنم، بنابراین منصرف شدم و به جای آن از روش brute force استفاده کردم: فقط همه چیز را تولید کنید و سپس برندگان را انتخاب کنید.
این همان ترفندی است که در مورد درخت BSP وجود دارد که در آن ما فقط همه چیز را در یک bigint بسته بندی می کنیم و سپس min را انتخاب می کنیم: مهم ترین بیت ها عمق هستند، بنابراین می توانیم فقط min را انتخاب کنیم تا برنده را پیدا کنیم. و از آنجایی که بار (به عنوان مثال، رنگ پیکسل) نیز بخشی از کلید است، ما حتی مجبور نیستیم دوباره به آن بپیوندیم! کمی هک به نظر می رسد، اما از آنجایی که این کار برای هر پیکسل است (و یک فریم Doom تنها 320*200=64000 پیکسل دارد)، باید مراقب باشیم که کار زیادی انجام ندهیم.
حتی با این بهینهسازی، همچنان گرانترین بخش فریم است: به طور متوسط 8.2 میلیثانیه، بیش از یک سوم کل فریم! و دقیقا به همین دلیل است که جان کارمک از آن اجتناب کرد. اما ما خوش شانس هستیم که اکنون ماشین هایی داریم که می توانند این کار را حتی در SQL اجرا کنند و همچنان به هدف 35 فریم در ثانیه برسند. آینده اکنون است، پیرمرد! .
در اینجا نمایی آبشار از خط لوله در مقایسه با هدف فریم 35 فریم در ثانیه Doom ارائه شده است.
در لپ تاپ من (Ryzen 7 PRO 7840U) معمولا حدود 60 فریم در ثانیه دریافت می کنم، اما در صحنه های بسیار شلوغ به 35 فریم در ثانیه کاهش می یابد.
گران ترین قسمت های خط لوله (تعجبی ندارد):
بدیهی است که رندر Doom در پایگاه داده ایده بدی است. اما چند زمینه وجود دارد که در واقع مناسب است و من تا پای جان از آنها دفاع خواهم کرد!
قبلا انتظار نداشتم که چقدر از ترجمه خصوصیات اقلام به مجموعه داده های رابطه ای لذت ببرم. به عنوان مثال، دیدن محتوای واقعی بازی شما بسیار آسان است، اما مهمتر از همه، تغییر آن نیز بسیار آسان است.
حتی انیمیشن هم داده است! در اینجا کل ماشین دولتی تفنگ ساچمه ای است:
ویژگیهای چیزهایی که فقط در یک جدول ذخیره میشوند، اصلاح همه چیز را واقعا آسان میکند. به کلیپ زیر نگاهی بیندازید که در آن من ناامید هستم که به اندازه کافی آسیب نمیزنم، و فقط تفنگ ساچمهای را تغییر دهید تا 500 گلوله را به طور همزمان شلیک کنید.
البته، ما میتوانستیم همه چیز را در فایلهایی به عنوان مثال ذخیره کنیم. JSON اما این بدان معنی است
خوب، اکنون ما با تمام این مشکلات برای پورت کردن Doom به SQL روبرو شدیم و حتی از بزرگترین نقطه قوت یک پایگاه داده استفاده نکردیم: شما یک سرور چند نفره رایگان دریافت می کنید! به من گوش کنید، ما چیزهای زیادی دریافت می کنیم که توسعه دهندگان بازی های سنتی باید خودشان را به صورت رایگان بسازند:
یک اسکریپت داور جداگانه پایتون ساعت 35 هرتز مشترک را درایو می کند و نقشه را می چرخاند. مشتریان پخش کننده به صورت آنلاین ورودی را ارائه می کنند.
با این حال، بخشی که من بیشتر از همه دوست دارم، اتمی بودن است: هر زمان که یک تیک بازی را اجرا می کنیم، فقط می توانیم بگوییم شروع تراکنش و در پایان commit. هر بازیکنی (Doom deathmatch تا 4 را پشتیبانی میکند) همچنان دید ثابتی دارد، چه به شکلی که دنیا قبل از شروع تراکنش tic به نظر میرسید، یا بعد از انجام کامل آن. هیچ به روز رسانی جزئی اعمال شده، اشکال فیزیک، یا اختلاف نظر در مورد اینکه آیا موشک واقعا اصابت کرده است یا خیر.
قسمت دوم که به طرز شگفت آوری زیبا بود، کنترل دسترسی بود. در حالی که sqldoom خود حدود 110 جدول و کمی بیش از 100 عملکرد دارد، چهار نقش بازیکن فقط از طریق چند توابع API کاملا تعریف شده مجاز به تعامل با آن هستند. ما فقط دسترسی به هر چیز دیگری را لغو می کنیم!
تابع ورودی که ورودی را از یک پخش کننده می گیرد مثال خوبی است:
در حالی که تابع مجاز است در جداول تغییرات ایجاد کند (تعریف کننده امنیت)، پخش کننده فقط مجاز است تابع را فراخوانی کند. تنها دستگیرههایی که دارند عبارتند از: حرکت رو به جلو (با فشار دادن؟)، strafe (فشردن یک/د؟)، آیا آنها در حال اجرا هستند؟، چرخش از طریق ماوس؟، آیا دکمه آتش فشار داده شده است؟، کدام سلاح انتخاب شده است؟، و آیا سعی میکنند یک دکمه را فشار دهند/یک در را باز کنند (فاصله فاصله)؟ ما حتی مجبور نیستیم به مقادیر ورودی پخش کننده اعتماد کنیم: این تابع ورودی ها را به مقادیر مجاز می چسباند.
عملکرد چند نفره نیز به طرز شگفت انگیزی خوب است: 3 هسته در هر کلاینت 35 فریم بر ثانیه پایدار می دهد و تیک بازی همچنان بسیار پایین تر از بودجه باقی می ماند. یک هسته اضافی برای درایور تیک اضافه کنید و یک ماشین 16 هسته ای به خوبی مجهز شده است تا یک بازی اصلی -altdeath doom deathmatch را اجرا کند.
نمونه عمومی در نقشه های قسمت 1 می چرخد و هر 10 دقیقه یک نقشه جدید ظاهر می شود. اگر هر چهار اسلات اشغال شده باشند، همچنان میتوانید مسابقه زنده را از کنسول SQL جستجو کنید. مسابقه زنده را پخش کنید یا پرس و جو کنید →
مطمئنا پایگاه داده ای که به زبان C++ نوشته شده و SQL را تفسیر می کند، بسیار ناکارآمد است و نمی تواند به C نزدیک شود؟ احتمالا نه، اما می خواستم ارزیابی کنم که واقعا چقدر دور است.
CedarDB یک سیستم پایگاه داده کامپایل کننده است: هر پرس و جو پیچیده (از طریق چندین مرحله) به LLVM IR کاهش می یابد و سپس به کد ماشین کامپایل می شود. بنابراین از خودم این سوال را پرسیدم: آن کد ماشین تولید شده چه تفاوتی با کد اصلی کامپایل شده linux_doom C دارد؟
نیمه بالایی منطق حرکت یک جسم و نحوه تأثیر حرکت آن را نشان می دهد. سمت چپ کد منبع اصلی Doom است، سمت راست اجرای SQLDoom را نشان می دهد. مقایسه یک به یک نیست زیرا منطق کمی متفاوت است، اما کد C به 48 دستورالعمل کامپایل می شود در حالی که SQLDoom 117 دستورالعمل را می گیرد. 42 مورد از این دستورالعملهای اضافی در واقع نتیجه را دوباره در یک جدول ذخیره میکنند (خطوط سبز)، که واضح است که C مجبور به انجام آن نیست.
بنابراین بدتر است، اشتباه نکنید، اما واقعا برای اینکه چند لایه انتزاعی معمولا بین SQL و CPU شما وجود دارد، خیلی بدتر نیست. برای چیزی که بهعنوان SQL شروع شد و قبل از رسیدن به LLVM از یک بهینهساز پرس و جو عبور کرد، شکاف را بهطور شگفتآوری کوچک یافتم.
منظورم این است که SQLDoom را با سلف Wolfenstein 3D مانند DOOMQL مقایسه کنید.
هر دو از یک موتور و محدودیتهای یکسان استفاده میکنند: SQL in، bitmap out. و اشتباه نکنید، رویکرد raycasting اولیه DOOMQL عالی است - فرمولبندی در SQL بسیار سادهتر است و وابستگیهای زیادی بین مراحل وجود ندارد - برای پردازش مبتنی بر مجموعه SQL بسیار مناسبتر است.
اما به نظر می رسد که "بهترین تناسب" همیشه بهترین نتایج را ندارد. رویکرد BSP-tree SQLDoom بسیار سریعتر است و وفاداری بصری آن در همان زمان بسیار بالاتر است. همه اینها به این دلیل است که جان کارمک به سختی فکر می کرد که چقدر می توانید با کمی دود و آینه از 486 خود خارج شوید.
و صادقانه بگویم، CedarDB نیز به این نتیجه رسید. زمانی که من DOOMQL را ساختم، موتور کمی کندتر بود و ما هنوز یک سیستم دسترسی مبتنی بر نقش نداشتیم.
این در Github در github.com/cedardb/sqldoom است.
از آن به بعد فقط README را دنبال کنید و باید SQLDoom خود را در کمترین زمان اجرا کنید!
یا، اگر همه اینها کار زیاد به نظر می رسد، فقط به یک مسابقه در نمونه عمومی بپیوندید:
متن اصلی (انگلیسی)
We ported the original Doom to SQL
Article URL: https://cedardb.com/blog/sqldoom/ Comments URL: https://news.ycombinator.com/item?id=49948300 Points: 162 # Comments: 22